socket 莫名其妙的断开连接?

之前有客户反馈,经常会收到客户端断开连接的提醒。影响聊天,希望能查下问题。开始我以为是用户网络波动,导致的连接断开,后来同事跟我反馈,网络正常的时候也会出现断开连接的现象,希望我查下服务器是否配置了什么,会话保持时长之类的参数。

问题重现

这个问题在c++端比较容易重现,在web端偶现,移动端却没发生过。难道是移动端一直没用户使用,所以他们也不知道?额,不能这样想,不然容易被打。一定是有人用的,可能移动端有啥不为人知的厉害操作?

问题分析

由于这个涉及的角色只有两个,server端和client端,至少目前来说,已经有两种client端都出现了问题,难道这俩端都写的有问题么?额,有一个是我写的,没弄清楚之前,不能怂。先从服务器端查起,检查相关配置,并没有发现有类似保持连接时间的配置,额。。。这就尴尬了。客户端也没有写超时自动断开的逻辑啊?几个人下午排查了半天,一直没发现问题到底是怎么回事儿。只能采用最笨的方法-抓包,然后请我们的好朋友wireshark分析下。同事在服务器端和客户端同时抓包,可是有时候就是这样,你越希望它重现,它反而越不出现。懊恼。。。

下班之前,CTO问查的如何了。大眼瞪小眼,不敢定结论。

他说他看下,第二天中午,cto拉我们去说这个问题,他找到原因了。

他给我们看异常断开连接前的包,发现断开连接之前会发两个包,每个包间隔是2s,上一条消息的间隔时间是20s,多次异常断开都是如此。这应该不是巧合,这个包来自服务器端,这说明服务器发完这两个包之后,没有得到响应,就把客户端断开了连接。这个实际上是服务器的tcp连接的keeplive机制,当服务器检测到一个socket端长时间不活动的时候,就会发送一个探测包检测client端是否还在,而当client端收到不回应的时候,会关闭连接,回收资源。linux内核跟这个相关的参数有三个:
tcp_keepalive_time(开启keepalive的闲置时长)
tcp_keepalive_intvl(keepalive探测包的发送间隔)
tcp_keepalive_probes (如果对方不予应答,探测包的发送次数)

那是不是这三个内核参数的配置问题呢?检查当前配置:

root@xxx:/# sysctl -a | grep keep
net.ipv4.tcp_keepalive_intvl = 2
net.ipv4.tcp_keepalive_probes = 2
net.ipv4.tcp_keepalive_time = 20

果然,跟猜想一样,问题出自这个配置,初始化服务器的时候,会有脚本自动调优。加上应用层上编写代码时,并没有设置此参数,覆盖系统的设置。所以导致了总是莫名其妙的自己断开。

真相大白,对cto的崇拜又多了几分,总能在众人迷惑的时候,站出来当指明灯。

解决方案:
1. 应用层增加socket保活参数配置,覆盖系统配置(完美)
2. 直接修改系统配置文件/etc/sysctl.conf,应用层增加心跳机制,空闲状态时,每隔19s发送一个心跳包过去(实际采用)。

顺便说一下,之前移动端确实没有发生断开连接的异常情况,是因为移动端的开发主动加过保活机制,赞一个。

附录:
tcp长连接和保活时间(keepalive)
keeplive详解

  • 16
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 当socket断开连接时,有多个原因可能会导致这种情况发生。其中一些原因可能是网络问题、服务器故障、客户端故障或者用户主动断开连接。在程序中,我们可以通过捕获异常来处理这种情况。在Python中,可以使用try-except语句来捕获异常,在发生异常时执行一些特定的操作,比如关闭socket连接、重新连接等。以下是一个简单的示例代码: ```python import socket HOST = 'localhost' PORT = 8000 try: # 创建socket连接 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) # 发送数据 s.sendall(b'Hello, world') # 接收数据 data = s.recv(1024) print('Received', repr(data)) except Exception as e: print(e) finally: # 关闭socket连接 s.close() ``` 在上面的代码中,我们使用了try-except语句来捕获异常。如果在连接、发送或接收数据的过程中发生了异常,程序会输出异常信息并关闭socket连接。如果没有发生异常,程序会正常关闭socket连接。 ### 回答2: 当Socket连接断开时,意味着建立的网络连接被中断或关闭。有几种情况会导致Socket连接断开: 1. 服务器或客户端异常关闭:如果服务器或客户端应用程序关闭或崩溃,Socket连接将会断开。这可能是由于程序中的bug、操作系统问题或网络中断引起的。 2. 网络中断:如果网络中断或出现问题,Socket连接也会断开。这可能是由于网络故障、网络设备故障或网络拥塞等原因引起的。 3. 超时:Socket连接在一定的时间内没有收到任何数据传输时,就会发生超时。超时可以是因为网络延迟、对方应用程序崩溃、服务器负载过重等原因导致的。 4. 手动关闭:应用程序可以通过调用Socket的close()方法来主动关闭连接。这通常在通信完成或不再需要连接时使用。 无论何种原因导致Socket连接断开,当连接断开时,通常会触发错误或异常,并且连接双方都会收到有关连接断开的通知。应用程序可以根据这些通知采取相应的措施,例如重新连接、重新建立资源或提示用户重新尝试连接。 ### 回答3: 当一个socket断开连接时,意味着通信的两个端点之间的连接已经被中断或关闭。这种情况可能由多种原因引起,如网络故障、通信错误、连接超时或用户操作等。 一旦发生socket断开连接,通信双方将无法继续进行数据交换。数据将无法传送到远程端口,并且对方也无法发送任何数据到本地端口。这也意味着任何未收到的数据将丢失,正在发送的数据也无法到达目的地。 在程序设计中,可以通过捕获特定的断开连接错误或异常来处理socket断开连接的情况。一般来说,当socket断开连接时,可以采取以下几种操作: 1. 重新建立连接:可以尝试重新连接到远程主机,重新建立通信链路。这通常需要重新创建socket对象,并重新绑定到远程主机的IP地址和端口号。 2. 进行错误处理:如果socket断开连接是由于网络故障等原因引起的,可以根据具体错误类型来处理异常。例如,可以记录错误日志、向用户显示错误信息或提示用户重新连接等。 3. 清理资源:当socket断开连接时,可能需要释放相关的资源,如关闭socket对象、释放内存或清理缓冲区。这可以防止资源泄露和占用。 总之,socket断开连接是在网络通信过程中常见的情况,需要注意处理,并根据具体情况采取相应的措施来处理错误和恢复通信。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值