您的位置:首页 > 理论基础 > 计算机网络

如何解决 Socket 连接超时

2017-11-11 21:28 351 查看
最近两天 项目其中一台IM服务器的IM验证出现问题,进行用户IM注册时出现连接超时问题;

重启服务后,可以进行用户的IM注册验证,没有出现超时问题;但是等到半个钟一个钟(时间不定);

结果还是会有连接超时问题,所有单单是重启解决不了问题,也不可能一有问题就去重启服务

问题一:

登录服务器后台,使用netstat -ant命令查看当前网络状态:(此图是禁用IPV6后截图)



发现,输出中没有IM验证绑定的端口9193;但服务却是在运行;

然后使用 lsof -i:9193 能够获取到打开的文件记录,说明端口是启动的 ;但是,记录中的type是IPV6

猜测是否是因为使用了IPV6连接方式导致的问题,然后逐一测试80,8080等端口,发现凡是IPV6连接方式都不会显示

接下来,选择禁用IPV6:

打开/etc/sysctl.conf

在文件末尾添加:

# 禁用整个系统所有接口的IPv6

  net.ipv6.conf.all.disable_ipv6 = 1

  # 禁用某一个指定接口的IPv6(例如:eth0, lo)

  net.ipv6.conf.lo.disable_ipv6 = 1

  net.ipv6.conf.eth0.disable_ipv6 = 1

  在 /etc/sysctl.conf 使这些更改生效,运行以下命令:

  $ sudo sysctl -p /etc/sysctl.conf

  或者直接重启。

问题二:

解决上述问题后,重启服务后,连接超时异常还是出现;

使用netstat -ant查看连接状态,出现close_wait 状态;该问题是由于服务端或者

客户端其中某一方手动关闭了连接,服务端没有收到断开连接的请求,所以报错;

只能去查看源码:

查看源码,发现客户端和服务端的socket源码,都没有写异常的处理方式;

然后修改server源码,在异常中加上判断:(客户端的socket请求一样添加了处理)

1.判断socket是否为空

2.判断socket是否关闭 (使用isClosed())

3.手动关闭未关闭的socket

打包升级服务端后,客户端连接注册,问题解决

来自网络:

SOCKET CLOSE_WAIT状态的说明:

CLOSE_WAIT出现的原因: 就是某一方在网络连接断开后,对等方没有检测到这个错误(对方断开)而没有调用 closesocket,导致了这个状态的出现;

 

断开连接的时候: 

      当发起主动关闭的左边这方发送一个FIN过去后,右边被动关闭的这方要回应一个ACK,
 这个ACK是TCP回应的(同时TCP向上层应用程序提交一个ERROR,导致上面的SOCKET的send
 或者recv返回SOCKET_ERROR),而不是应用程序发送的,此时,被动关闭的一方就处于
 CLOSE_WAIT状态了。如果此时被动关闭的这一方不再继续调用closesocket,
 那么他就不会发送接下来的FIN,导致自己老是处于CLOSE_WAIT。只有被动关闭的这一方
 调用了closesocket,才会发送一个FIN给主动关闭的这一方,同时也使得自己的状态变迁
 为LAST_ACK,待接收到主动关闭方发送的ACK后,才会将SOCKET置为CLOSED。 
 
 首先我们知道,如果我们的Client程序处于CLOSE_WAIT状态的话,说明套接字是被动关闭的!

因为如果是Server端主动断掉当前连接的话,那么双方关闭这个TCP连接共需要四个packet:

       Server ---> FIN ---> Client

       Server <--- ACK <--- Client

    这时候Server端处于FIN_WAIT_2状态;而我们的程序处于CLOSE_WAIT状态。

       Server <--- FIN <--- Client

这时Client发送FIN给Server,Client就置为LAST_ACK状态。

        Server ---> ACK ---> Client

Server回应了ACK,那么Client的套接字才会真正置为CLOSED状态。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java 网络 异常