如何判断Socket的实时连接

如何判断Socket的实时连接,第1张

看到这个标题,估计很多人会说用socketisConnected()或者socketisClosed()等方法来判断就行了,但事实上这些方法都是访问socket在内存驻留的状态,当socket和服务器端建立链接后,即使socket链接断掉了,调用上面的方法返回的仍然是链接时的状态,而不是socket的实时链接状态,下面给出例子证明这一点。
服务器端:
package comcscserver;
import javanet;
/
@description 从这里启动一个服务端监听某个端口
@author csc
/
public class DstService {
public static void main(String[] args) {
try {
// 启动监听端口 30000
ServerSocket ss = new ServerSocket(30000);
// 没有连接这个方法就一直堵塞
Socket s = ssaccept();
// 将请求指定一个线程去执行
new Thread(new DstServiceImpl(s))start();
} catch (Exception e) {
eprintStackTrace();
}
}
}
这里我设置了启动新线程来管理建立的每一个socket链接,此处我们设置收到链接后10秒端来链接,代码如下:
package comcscserver;
import javanetSocket;
/
@description 服务的启动的线程类
@author csc
/
public class DstServiceImpl implements Runnable {
Socket socket = null;
public DstServiceImpl(Socket s) {
thissocket = s;
}
public void run() {
try {
int index = 1;
while (true) {
// 5秒后中断连接
if (index > 10) {
socketclose();
Systemoutprintln("服务端已经关闭链接!");
break;
}
index++;
Threadsleep(1 1000);//程序睡眠1秒钟
}
} catch (Exception e) {
eprintStackTrace();
}
}
}
以上是服务端代码,下面写一个客户端代码来测试:
package comcscclient;
import javanet;
/
@description 客户端打印链接状态
@author csc
/
public class DstClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("127001", 8001);
socketsetKeepAlive(true);
socketsetSoTimeout(10);
while (true) {
Systemoutprintln(socketisBound());
Systemoutprintln(socketisClosed());
Systemoutprintln(socketisConnected());
Systemoutprintln(socketisInputShutdown());
Systemoutprintln(socketisOutputShutdown());
Systemoutprintln("------------我是分割线------------");
Threadsleep(3 1000);
}
} catch (Exception e) {
eprintStackTrace();
}
}
}
先运行服务端代码,再运行客户端代码,我们会在客户端代码的控制台看到如下信息:
true
false
true
false
false
------------我是分割线------------
从连接对象的属性信息来看,连接是没有中断,但实际链接已经在服务端建立链接10秒后断开了。这说明了上述几个方法是不能实时判断出socket的链接状态,只是socket驻留在内存的状态。其实,此时如果调用流去读取信息的话,就会出现异常。
其实,想要判断socket是否仍是链接状态,只要发一个心跳包就行了,如下一句代码:
socketsendUrgentData(0xFF); // 发送心跳包
关于心跳包的理论可以去google一下,我给出点参考:心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包。 用来判断对方(设备,进程或其它网元)是否正常运行,采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经离线。用于检测TCP的异常断开。基本原因是服务器端不能有效的判断客户端是否在线,也就是说,服务器无法区分客户端是长时间在空闲,还是已经掉线的情况。所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内没有收到客户端信息则视客户端断开。 比如有些通信软件长时间不使用,要想知道它的状态是在线还是离线就需要心跳包,定时发包收包。发包方:可以是客户也可以是服务端,看哪边实现方便合理,一般是客户端。服务器也可以定时发心跳下去。一般来说,出于效率的考虑,是由客户端主动向服务器端发包,而不是服务器向客户端发。客户端每隔一段时间发一个包,使用TCP的,用send发,使用UDP的,用sendto发,服务器收到后,就知道当前客户端还处于“活着”的状态,否则,如果隔一定时间未收到这样的包,则服务器认为客户端已经断开,进行相应的客户端断开逻辑处理!
既然找到了方法,我们就在测试一下,服务端代码无需改动,客户端代码如下:
package comcscclient;
import javanet;
/
@description 客户端打印链接状态
@author csc
/
public class DstClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("127001", 30000);
socketsetKeepAlive(true);
socketsetSoTimeout(10);
while (true) {
socketsendUrgentData(0xFF); // 发送心跳包
Systemoutprintln("目前是处于链接状态!");
Threadsleep(3 1000);//线程睡眠3秒
}
} catch (Exception e) {
eprintStackTrace();
}
}
}
重新运行客户端程序,看到控制台打印如下信息:
目前是处于链接状态!
目前是处于链接状态!
目前是处于链接状态!
javanetSocketException: Invalid argument: sendat javanetPlainSocketImplsocketSendUrgentData(Native Method)at javanetPlainSocketImplsendUrgentData(PlainSocketImpljava:550)at javanetSocketsendUrgentData(Socketjava:928)at comclientDstClientmain(DstClientjava:14) 这说明当执行“socketsendUrgentData(0xFF);”这个语句时,socket链接断开了,执行失败抛出了异常。
另外注意,心跳包只是用来检测socket的链接状态,并不会作为socket链接的通信内容,这点应当注意。

事件背景  ubuntu 系统

        IP下链接服务器,客户端访问 服务器 出现问题 

路由器端口映射 将服务器通过IP 映射至公网 网络检查  需验证 UDP 协议的端口是否 可以通过公网链接至服务器进行发包

准备  两台服务器   一台服务器在 此IP下进行端口映射 使用UDP协议映射至公网    一台服务器不在此IP下且不在同网段下 

需要实现  两台服务器 之间 通过UDP 链接进行发包  

两台服务器 安装 NC 工具     sudo apt-get install netcat-traditional -y    安装后  默认开启此工具

需验证的IP下服务器   通过 命令   nc -lu ip port  本地IP 需要验证的端口  

配合测试服务器  安装后   使用 nc -u ip port 公网IP 需要验证的端口

IP下的服务器
配合测试服务器
连接实现 后两服务器 可以实现互相发送 字符  验证结果 此IP下的端口50000  可以实现连接

而同期的TCP 则简单很多  直接通过自己的电脑   telnet IP 端口   端口连接接通后 会跳转 一个窗口 代表连接接通

否则 为不同

服务器 主对话框中有一个按钮,点击按钮,进入另外一个对话框DLG1,DLG1对话框完成TCP/IP的监听,数据传输客户端 定时连接服务器定义一个全局变量uchar tcpflag=0;为0 说明没有连接,为1说明连接成功服务器程序:点击监听按钮,开始监听客户端的连接,等DLG1关闭的时候,在销毁函数中,发送一个字符串dunkai,通知客户端,服务器已经断开客户端程序:1、在定时中,判断tcpflag是否为0,如果是,说明没有连接,创建与服务器的连接,连接成功后,tcpflag=1;推出定时2、在TCP/IP接收线程中,判断接收到的数据是否为'duankai'字符串,如是,说明连接断开,令tcpflag=0;注意:在设置标志位之前要加延时


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10382776.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-08
下一篇 2023-05-08

发表评论

登录后才能评论

评论列表(0条)

保存