Netty使用TCP连接错误
欢迎关注驿外残香 | HC的博客
表面原因
在与嵌入式组进行TCP连接时发生未知错误导致服务器接收不到数据。并且Netty封装的exceptionCaught方法以及channelInactive方法捕获不到任何的报错异常以及连接断开情况。
探寻主线
一开始使用tcpdump -iany tcp port 8090
对8090端口进行抓包,发现在经过三次握手之后服务器与客户端之间就开始了一来一往的包传递,在经过了几个小时之后,包之间的传递戛然而止,查看最后几个包的信息,并没有看到有关断开连接的四次握手操作。
Linux操作环境中使用lsof -i:port
检测打开套接字的状态。发现除了一条用于监听8090端口连接的线程外,该端口还建立了多条处于ETABLISHED状态的线程。
由于客户端只有一个,在查阅了资料发现在一台客户端与服务器的TCP连接中,处于连接状态,即ETABLISHED状态的线程应该只有一条。
于是尝试使用kill -9 port
杀死了目前正在运行的Java项目,同时可以观测到除了监听线程被关闭外,其他8090端口的线程都处于FIN-WAIT-1状态,即正在等待客户端返回ACK与FIN。但很明显,客户端没能够返回该信号而导致该线程一直处于该状态。直到几分钟过去了,服务器强制关闭了这些线程。
此处查看了网络上的资料,发现当服务器出现很多ESTABLISHED状态时,可能是这时候若客户端断开的时候未发送FIN包,则服务端处还是显示ESTABLISHED状态;
结果客户端重新连接服务器。而新连接上来的客户端(也就是刚才断掉的重新连上来了)在服务端肯定是ESTABLISHED;
如果客户端重复的上演这种情况,那么服务端将会出现大量的假的ESTABLISHED连接和CLOSE_WAIT连接。最终结果就是新的其他客户端无法连接上来,但是利用netstat还是能看到一条连接已经建立,并显示ESTABLISHED,但始终无法进入程序代码。
这时想起最初的时候嵌入式组为了防止服务器的断线,每隔几分钟便断开连接并重新连接。此时可能由于网络上的问题,导致断开的信息服务器未能接收到,这样就造成了上述的情况。在本地电脑跑的时候没有这么频繁的断开事故可能就是网络的原因。
那么阿里云的网络有这么差么?经过下面测试。。emmm。。看来发送个几百条断开信号但因为网络原因漏掉几条也没什么不对的。。
解决方案
使用正则表达式对嵌入式发送的数据进行匹配,若发现不符合数据格式则抛出异常并断开连接,防止影响后面的数据库操作。
\b\w*:V_\d:[0-9]+[.][0-9]*,I_\d:[0-9]+[.][0-9]*,P_\d:[0-9]+[.][0-9]*,PF_\d:[0-9]+[.][0-9]*,F_\d:[0-9]+[.][0-9]*,W_\d:[0-9]+[.][0-9]*\bend
与嵌入式端协调,取消每隔几分钟断开重连的机制。
使用心跳机制,当服务器在一定时间内没有接收到客户端发来的信息时则断开连接,同时在接收到客户端信息的同时发送响应信息,让嵌入式方面进行相应的操作。