新手发帖,很多方面都是刚入门,有错误的地方请大家见谅,欢迎批评指正
看到这个标题,计估很多人会说用socket.isConnected()或者socket.isClosed()等方法来断判就好了,但事实上这些方法都是问访socket在存内驻留的状态,当socket和服务器端建立链接后,即使socket链接断掉了,用调面上的方法回返的仍然是链接时的状态,而不是socket的实时链接状态,面下给出例子证明这一点。
服务器端:
package com.csc.server;import java.net.*;/** * @description 从这里启动一个服务端监听某个口端 * @author csc */public class DstService { public static void main(String[] args) { try { // 启动监听口端 30000 ServerSocket ss = new ServerSocket(30000); // 没有连接这个方法就始终梗塞 Socket s = ss.accept(); // 将求请指定一个线程去行执 new Thread(new DstServiceImpl(s)).start(); } catch (Exception e) { e.printStackTrace(); } }}
这里我设置了启动新线程来理管建立的每个socket链接,此处我们设置收到链接后10秒端来链接,代码如下:
package com.csc.server;import java.net.Socket;/** * @description 服务的启动的线程类 * @author csc */public class DstServiceImpl implements Runnable { Socket socket = null; public DstServiceImpl(Socket s) { this.socket = s; } public void run() { try { int index = 1; while (true) { // 5秒后中断连接 if (index > 10) { socket.close(); System.out.println("服务端经已关闭链接!"); break; } index++; Thread.sleep(1 * 1000);//程序眠睡1秒钟 } } catch (Exception e) { e.printStackTrace(); } }}
以上是服务端代码,面下写一个客户端代码来测试:
package com.csc.client;import java.net.*;/** * @description 客户端印打链接状态 * @author csc */public class DstClient { public static void main(String[] args) { try { Socket socket = new Socket("127.0.0.1", 30000); socket.setKeepAlive(true); socket.setSoTimeout(10); while (true) { System.out.println(socket.isBound()); System.out.println(socket.isClosed()); System.out.println(socket.isConnected()); System.out.println(socket.isInputShutdown()); System.out.println(socket.isOutputShutdown()); System.out.println("------------我是分割线------------"); Thread.sleep(3 * 1000); } } catch (Exception e) { e.printStackTrace(); } }}
先行运服务端代码,再行运客户端代码,我们会在客户端代码的控制台看到如下信息:
truefalsetruefalsefalse------------我是分割线------------
从连接对象的性属信息来看,连接是没有中断,但际实链接经已在服务端建立链接10秒后开断了。这说明了上述几个方法是不能实时断判出socket的链接状态,只是socket驻留在存内的状态。其实,此时如果用调流去读取信息的话,就会出现异常。
其实,想要断判socket否是还是链接状态,只要发一个跳心包就好了,如下一句代码:
socket.sendUrgentData(0xFF); // 发送跳心包
关于跳心包的理论可以去google一下,我给点出参考:跳心包就是在客户端和服务器间准时通知对方自己状态的一个自己义定的命令字,按照必定的间时间隔发送,类似于跳心,所以叫做跳心包。 用来断判对方(设备,进程或其它网元)否是正常行运,采取准时发送单简的通信包,如果在指准间时段内未收到对方响应,则断判对方经已离线。于用检测TCP的异常开断。基本原因是服务器端不能有效的断判客户端否是在线,也就是说,服务器法无分区客户端是长间时在闲空,还是经已掉线的情况。所谓的跳心包就是客户端准时发送单简的信息给服务器端诉告它我还在而已。代码就是每隔几分钟发送一个牢固信息给服务端,服务端收到后复回一个牢固信息如果服务端几分钟内没有收到客户端信息则视客户端开断。 比如有些通信软件长间时不应用,要想晓得它的状态是在线还是离线就需要跳心包,准时发包收包。发包方:可是以客户也可是以服务端,看哪边现实便利公道,一般是客户端。服务器也可以准时发跳心下去。一般来说,出于率效的虑考,是由客户端主向动服务器端发包,而不是服务器向客户端发。客户端每隔一段间时发一个包,应用TCP的,用send发,应用UDP的,用sendto发,服务器收到后,就晓得以后客户端还处于“着活”的状态,否则,如果隔一准间时未收到这样的包,则服务器以为客户端经已开断,停止响应的客户端开断逻辑理处!
既然找到了方法,我们就在测试一下,服务端代码无需修改,客户端代码如下:
package com.csc.client;import java.net.*;/** * @description 客户端印打链接状态 * @author csc */public class DstClient { public static void main(String[] args) { try { Socket socket = new Socket("127.0.0.1", 30000); socket.setKeepAlive(true); socket.setSoTimeout(10); while (true) { socket.sendUrgentData(0xFF); // 发送跳心包 System.out.println("前目处于链接状态!"); Thread.sleep(3 * 1000);//线程眠睡3秒 } } catch (Exception e) { e.printStackTrace(); } }}
重新行运客户端程序,看到控制台印打如下信息:
服务端程序行运10秒后再当行执“socket.sendUrgentData(0xFF);”语句时,socket链接开断了,所以会抛出异常。 另外注意,跳心包只是用来检测socket的链接状态,并不会作为socket链接的通信内容,这点应该注意。 转载请注明出处:
文章结束给大家分享下程序员的一些笑话语录: 人脑与电脑的相同点和不同点,人脑会记忆数字,电脑也会记忆数字;人脑会记忆程序,电脑也会记忆程序,但是人脑具有感知能力,这种能力电脑无法模仿,人的记忆会影响到人做任何事情,但是电脑只有程序软件。比尔还表示,人脑与电脑之间最重要的一个差别就是潜意识。对于人脑存储记忆的特别之处,比尔表示,人脑并不大,但是人脑重要的功能是联络,人脑会把同样的记忆存储在不同的地方,因此记忆读取的速度就不相同,而这种速度取决于使用的频率和知识的重要性。人脑的记忆存储能力会随着年龄增长而退化,同时记忆的质量也会随着年龄退化。经典语录网