Socket 编程中,如何处理超时问题?

在Socket编程中,经常需要处理超时问题,主要包括:

  1. 连接超时:客户端连接服务端超过一定时间未成功,视为连接超时。
  2. 读取超时:客户端读取服务端数据超过一定时间无响应,视为读取超时。
  3. 写入超时:客户端向服务端写入数据超过一定时间未成功,视为写入超时。
  4. 心跳超时:两次心跳包之间的时间间隔超过一定阈值,视为心跳超时。

处理超时问题的主要方法有:

  1. 设置超时时间:为Socket的连接、读取、写入等操作设置超时时间,超时后视为失败。
  2. 重试机制:当操作超时后,客户端可以重新执行该操作,尝试重新连接或读取数据等。
  3. 心跳检测:客户端定期向服务端发送心跳包,如果超过一定时间未收到心跳回复,视为心跳超时。
  4. 重新连接:当连接或心跳超时时,客户端重新连接服务端,以恢复网络通信。
  5. 超时重传:当客户端在一定时间内未收到对已发送数据的确认,主动重传数据,以防数据丢失。

代码示例:

// 客户端
Socket socket = new Socket();
socket.setSoTimeout(5000);     // 设置超时时间  
socket.connect(new InetSocketAddress("127.0.0.1", 8000));

InputStream in = socket.getInputStream();  
try {
    byte[] data = new byte[1024];
    int len; 
    while ((len = in.read(data)) != -1) {  // 读取数据
        // ...
    }
} catch (SocketTimeoutException e) {
    // 读取超时,重新读取
    in.read(data);     
} 

OutputStream out = socket.getOutputStream();
try {
    out.write(data);     // 写入数据
} catch (SocketTimeoutException e) {   
    // 写入超时,重传数据
    retransmit(data);
}

long lastHeartBeat = System.currentTimeMillis(); 
while (connected) {
    if (System.currentTimeMillis() - lastHeartBeat > heartBeatInterval * 2) {
        // 心跳超时,重新连接
        socket.close();
        socket = new Socket();
        socket.connect(new InetSocketAddress("127.0.0.1", 8000));
        lastHeartBeat = System.currentTimeMillis();
    }
    // 定期发送心跳
}