现在都搞升级,本人也也使用JDK6进行开发。在开发工程中对Socket进行管理时对于这个连接的超时和是否失效进行研究。结果网上的资料很是让人失望,可以说google和百度下来,前几页原创很少都是抄袭。
说正经的,对于连接超时和失效肯定会想到设置超时时间和判断连接是否可用。但是设置超时时间后起作用是在调用read方法的时候,如果只是设置了超时时间却没有调用read,那么就算服务端中断连接,客户端也是无法得知的。而且就算read异常,当前的连接仍然是有效的。
我们来看如下代码运行后再继续:
服务端:
package com.service; import java.net.*; /** * @说明 从这里启动一个服务端监听某个端口 * @author 崔素强 */ public class DstService { public static void main(String[] args) { try { // 启动监听端口 8001 ServerSocket ss = new ServerSocket(8001); // 没有连接这个方法就一直堵塞 Socket s = ss.accept(); // 将请求指定一个线程去执行 new Thread(new DstServiceImpl(s)).start(); } catch (Exception e) { e.printStackTrace(); } } }
然后我们来看执行类,执行类在收到连接5秒后中断连接:
package com.service; import java.net.Socket; /** * @说明 服务的具体执行类 * @author 崔素强 */ 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 > 5) { socket.close(); System.out.println("服务端已经将连接关闭!"); break; } index++; Thread.sleep(1 * 1000); } } catch (Exception e) { e.printStackTrace(); } } }
我们在写一个客户端进行实验:
package com.client; import java.net.*; /** * @说明 服务的客户端,会请求连接并实时打印连接对象的一些信息,但是不会进行流的操作 * @author 崔素强 */ public class DstClient { public static void main(String[] args) { try { Socket socket = new Socket("127.0.0.1", 8001); 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(); } } }
至于输出结果,虽然服务端已经中断连接,但是客户端一直输出下面内容:
true false true false false ------------------------
从连接对象的属性信息来看,连接似乎没有中断。但实际虽然内存对象可用,但是物理连接已经失效。所以和网上其他抄袭来抄袭去的说法一样,靠连接对象属性来判断连接的可用性是不可行的。
大家会说那就判断调用read方法是否报错呗。我之前有文章已经讨论了关于调用网络里面流的一些内容,在没有判断这个流可用之前,我们是不会调用read方法的,当然具体你是怎么做的我不知道我在说我的情况!
读取网络数据流时的那个方法是这样的:
public static byte[] inputStreamToByte(InputStream inStream) throws Exception { int count = 0; int haveCheck = 0; // 如果在网络传输中数据没有完全传递,则方法返回0 while (count == 0) { count = inStream.available(); haveCheck++; if (haveCheck >= 50) return null; } byte[] b = new byte[count]; inStream.read(b); return b; }
就是说我们不会直接调用read方法,而available方法在流没有完整和网络中断时都会返回0,不会报错。
就是说就算你设置超时时间设置保持连接这些东西,只要你没有调用read的机会,你的程序就不会出问题。当然如果程序一直不调用read方法,那这个程序可真的够扯淡的了。
其实只要在使用这个连接的时候判断这个连接的可用性就行了,不要等着什么超时。
判断连接可用虽然网上一大片,其实就是那么回事,手动发送心跳包。
socket.sendUrgentData(0xFF); // 发送心跳包
乳沟你的连接已经中断,那么这个方法就会报错。
至于什么是心跳包,直接上理论吧。
心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包。 用来判断对方(设备,进程或其它网元)是否正常运行,采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经离线。用于检测TCP的异常断开。基本原因是服务器端不能有效的判断客户端是否在线,也就是说,服务器无法区分客户端是长时间在空闲,还是已经掉线的情况。所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内没有收到客户端信息则视客户端断开。 比如有些通信软件长时间不使用,要想知道它的状态是在线还是离线就需要心跳包,定时发包收包。发包方:可以是客户也可以是服务端,看哪边实现方便合理,一般是客户端。服务器也可以定时发心跳下去。一般来说,出于效率的考虑,是由客户端主动向服务器端发包,而不是服务器向客户端发。客户端每隔一段时间发一个包,使用TCP的,用send发,使用UDP的,用sendto发,服务器收到后,就知道当前客户端还处于“活着”的状态,否则,如果隔一定时间未收到这样的包,则服务器认为客户端已经断开,进行相应的客户端断开逻辑处理!
当然不能单纯理解心跳包就是往对方放松数据,因为心跳包是用于状态验证的,不是真实的数据。
我们来看如下例子,服务端不变:
package com.client; import java.net.*; /** * @说明 服务的客户端,会请求连接并实时打印连接对象的一些信息,但是不会进行流的操作 * @author 崔素强 */ public class DstClient { public static void main(String[] args) { try { Socket socket = new Socket("127.0.0.1", 8001); socket.setKeepAlive(true); socket.setSoTimeout(10); while (true) { socket.sendUrgentData(0xFF); // 发送心跳包 System.out.println("目前是正常的!"); Thread.sleep(3 * 1000); } } catch (Exception e) { e.printStackTrace(); } } }
看到控制台的输出:
目前是正常的! 目前是正常的! java.net.SocketException: Invalid argument: send at java.net.PlainSocketImpl.socketSendUrgentData(Native Method) at java.net.PlainSocketImpl.sendUrgentData(PlainSocketImpl.java:550) at java.net.Socket.sendUrgentData(Socket.java:928) at com.client.DstClient.main(DstClient.java:14)
那就是说,只要你的服务端断了,调用方法就会出错!
至于我说的他不会作为可见的数据你可以更改服务端代码打印客户端内容,你会发现服务端不会将心跳包内容展示给你!
InputStream ips = socket.getInputStream(); byte[] bt = inputStreamToByte(ips); if(null != bt) System.out.println(new String(bt)); else System.out.println("Bt is null"); System.out.println("****************************");
bt会一直是Null。为什么?因为我说的是对的!
哥通过示例说问题,也许不对有纰漏,但是咱绝对不去Copy,因为咱已经看厌了Copy!
请您到ITEYE看我的原创:http://cuisuqiang.iteye.com
或支持我的个人博客,地址:http://www.javacui.com
相关推荐
- **网络监听**:使用`ConnectivityManager`监控网络状态变化,但这种方法只能检测到设备的网络连接是否可用,不能判断特定Socket连接的状态。 以下是一个简单的示例代码,展示如何使用心跳机制检测网络断开: ``...
在处理大量并发连接时,为了提高性能和资源利用率,通常会引入连接池的概念,这就是"BIO Socket连接池"的核心所在。 BIO( Blocking Input/Output,阻塞I/O)是Java原生I/O模型的一种,它在处理高并发场景时效率较...
1. **建立Socket连接**:客户端使用`Socket`类的构造函数,指定服务器的IP地址和端口号,建立到服务器的连接。 2. **心跳包设计**:定义心跳包的格式,例如可以是一个简单的JSON对象,包含时间戳和"ping"或"pong"的...
下面来介绍判断非阻塞SOCKET是否已经断开的几种方法: 注意要区分不同操作系统分别进行测试, 包括WINDOWS, LINUX和UNIX会各有不同。 在WINDOWS下比较简单,可以使用FD_CLOSE事件判断SOCKET是否已经断开 view ...
本文将深入探讨SOCKET中的`accept`函数,该函数是服务器端等待并接受客户端连接的关键步骤。 #### 二、accept函数概述 `accept`函数是服务器端处理客户端连接请求的核心方法之一,其主要作用是从内核中取出已经建立...
如果在一定时间内没有数据交换,服务器可能会认为连接失效并关闭。 3. **服务器负载过高**:当FMS服务器处理过多请求时,可能会因为资源耗尽而断开部分连接。 4. **RTMP会话过期**:某些服务器可能设置了会话持续...
三次握手是为了确保连接的可靠性,防止已失效的连接请求报文突然又传到了服务端,导致服务端误认为新的连接请求。具体过程如下: 1. 第一次握手:客户端发送一个带有SYN(同步序列编号)标志的数据包给服务器,请求...
5. **连接断开**:如果经过多次重试仍然没有收到响应,TCP协议会认为连接已经失效,并主动发送一个RST报文断开连接。 #### 四、实现示例 接下来,我们将展示一段C++代码示例,该示例演示了如何在Windows环境下设置...
5. 连接的健康检查:定期对池中的连接进行健康检查,发现失效的连接会进行移除和重建,确保提供给应用的都是可用的连接。 6. 分布式环境支持:虽然BoneCP本身不直接支持分布式环境,但可以通过配置中间件如Apache ...
三次握手确保了连接的可靠性,防止已失效的连接请求报文突然又传到了服务端,而四次挥手的原因是TCP的全双工特性,双方都需要各自独立地关闭连接。 在Socket编程中,理解这些基础知识至关重要,因为它们决定了网络...
1. **心跳机制**:为防止网络延迟或断开导致的连接失效,需要定期发送心跳包,检测连接状态。 2. **线程管理**:Socket通信通常涉及多线程,需要妥善处理读写操作,避免阻塞主线程。 3. **数据序列化与反序列化**...
在处理大量Socket连接时,可能会遇到如`WSAENETDOWN`(网络子系统失效)或`WSA_NOT_ENOUGH_MEMORY`(内存不足)这样的错误。为了处理大量的并发连接,可能需要使用线程池来管理多个线程,每个线程处理一组套接字的...
为了保持连接活跃,通常需要设置心跳机制,防止网络中断导致的连接失效。 五、心跳机制 心跳机制是长连接中必不可少的部分,用于检测连接是否仍然有效。客户端定期发送心跳包到服务器,服务器在一定时间内未收到...
三次握手涉及SYN、SYN+ACK和ACK报文段,确保了连接的可靠性,防止已失效的连接请求报文突然又传到了服务器。四次挥手则用于关闭连接,涉及FIN、ACK、FIN+ACK报文段,确保数据传输完毕且双方都准备好断开连接。实验...
测试过程中,确保测试板上的铜片与Socket底部的弹片充分接触是非常关键的步骤。完成以上步骤后,进入AutoLearning确认测试板,确保所有设置无误后,可以进行开短路测试。这通常涉及到使用特定的测试软件,根据测试板...
三次握手确保了连接的可靠性,防止已失效的连接请求报文突然又传到了服务端,而四次挥手则用于释放连接。在不同阶段,TCP 连接的状态也会发生变化,例如 SYN_SENT、SYN_RCVD、ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2、...
KeepAlive是一种检测TCP连接状态的技术,主要用于避免由于网络故障或其他原因导致的连接失效问题。它通过定期发送小的数据包来检查对端是否仍然处于活动状态。 #### 三、KeepAlive配置参数 Linux系统中,可以通过...
这种机制确保了两端都准备好进行通信的状态,同时也防止了已失效的连接请求报文突然又传送到了服务器的情况。 ##### 2) 基于UDP客户—服务器程序设计基本框架 UDP是一种无连接的协议,因此它没有类似于TCP的“三次...
CAsyncSocket类提供了各种错误代码,例如WSAECONNRESET表示连接被远程主机重置,WSAENETDOWN表示网络子系统失效等。在编程过程中,我们需要捕获并适当地处理这些错误。 五、关闭与清理 在完成通信后,记得关闭套接...
它们通过Socket连接到服务器,将文件数据分割成数据块并发送,或者向服务器请求特定文件的数据块。 3. **文件分片**:为了提高存储效率和容错性,文件通常会被分成多个数据块,每个数据块可能被存储在不同的服务器...