Chinaunix

标题: 断开的TCP连接为什么还存在ESTABLISHED? [打印本页]

作者: zhanghua111    时间: 2005-11-05 22:07
标题: 断开的TCP连接为什么还存在ESTABLISHED?
最近在linux下写了个http代理程序,代理是通过多线程实现的,后来进行压力测试后发现,客户端已经断开了所有的连接,但是在代理的机器上用netstat还能看到ESTABLISHED状态的连接存在,而且一些子线程也没有正常退出,一直存在,网络状态也一直是ESTABLISHED,请大家帮忙分析一下原因,谢谢了
作者: xujg    时间: 2005-11-06 03:21
服务端close了吗
作者: xiaofei104    时间: 2005-11-06 09:38
我也遇到过一样的问题,不过问题时解决了,但是不清楚为什么会这样?

http://bbs.chinaunix.net/viewthr ... ge=1&highlight=
作者: yhch    时间: 2005-11-06 13:11
这个现象是正常的吧?如果Client死机的话Server不会知道的。Client重新开机后连接依然存在,仍然能正常通讯。如果是服务器死掉重新开机后,Client向Server发送数据,则服务器回应一个FIN断开连接。
我觉得定时在Server和Client之间发送心跳检测数据可以解决问题。
作者: sickcat2004    时间: 2005-11-06 14:38
后遗症?
作者: zhanghua111    时间: 2005-11-06 15:38
标题: 回复 3楼 xiaofei104 的帖子
能说说是如何解决的吗?这个问题我一直很头疼
作者: zhanghua111    时间: 2005-11-06 15:44
原帖由 yhch 于 2005-11-6 13:11 发表
这个现象是正常的吧?如果Client死机的话Server不会知道的。Client重新开机后连接依然存在,仍然能正常通讯。如果是服务器死掉重新开机后,Client向Server发送数据,则服务器回应一个FIN断开连接。
我觉得定时在 ...

client端是运行一段时间后停止的,按理说,我的代理程序是使用select对recv进行超时限制的,那为什么我用gdb对那么没有停止的线程进行调试时,提示是在sock_read函数中?
作者: zhanghua111    时间: 2005-11-06 15:52
贴上GDB的信息:
(gdb) where
#0  0x420daca4 in read () from /lib/i686/libc.so.6
#1  0x402b7b18 in __libc_internal_tsd_get () from /lib/i686/libpthread.so.0
#2  0x0809a87e in sock_read ()
#3  0x08360ed8 in ?? ()
(gdb)
作者: xiaofei104    时间: 2005-11-06 18:58
原帖由 yhch 于 2005-11-6 13:11 发表
这个现象是正常的吧?如果Client死机的话Server不会知道的。Client重新开机后连接依然存在,仍然能正常通讯。如果是服务器死掉重新开机后,Client向Server发送数据,则服务器回应一个FIN断开连接。
我觉得定时在 ...


你的说法肯定是不正确的。

1。在正常情况下是不会出现这个问题的。你可以自己写一个简单的Client/Server程序试试,Client断了,服务器端一定可以知道。因为你的服务器端一直在等待客户端的数据。

2.这个问题在有多线程的时候可能比较容易出现。

To:楼主:

1。因为我的Client/Server都是自己写的。所以我的做法是在Client中加了一个钩子去显示的close掉socket.而不是依赖于进程的关闭时候的资源释放。

2。你的情况可以试试将线程设置为守护线程,将socket资源设置为线程内的一个变量,而非一个全局的,在多个线程间共享的。
作者: xujg    时间: 2005-11-07 09:10
原帖由 xiaofei104 于 2005-11-6 18:58 发表

1。因为我的Client/Server都是自己写的。所以我的做法是在Client中加了一个钩子去显示的close掉socket.而不是依赖于进程的关闭时候的资源释放。

2。你的情况可以试试将线程设置为守护线程,将socket资源设置为线程内的一个变量,而非一个全局的,在多个线程间共享的。


1."client是否close"和"server上的连接显示established"是没有关系的
  就像你说的,连接断了,server是肯定知道的,因为select()的返回是可读,read()的返回是0

2.这个完全没有必要吧,每个处理连接的线程在知道自己所对应的连接断开后,自己可以先close了再退出

我觉得LZ的问题可能在于server对连接的处理流程,你的server是否时刻在监控着这个连接?
比如每个线程的处理可以大体是这样的

  1. while(1)
  2. {
  3.     pthread_testcancel();
  4.        
  5.     if(select(..))  //sleep()可以在这里实现
  6.     {
  7.         int ret = read(...);
  8.                
  9.         if(ret < 0)  //read()出错
  10.         {
  11.             //
  12.             close(sockfd);
  13.             pthread_exit();           
  14.         }
  15.         else if (ret == 0)  //连接断开
  16.         {
  17.             //
  18.             close(sockfd);
  19.             pthread_exit();         
  20.         }
  21.         else  //正确
  22.         {
  23.             //
  24.         }
  25.     }
  26. }
复制代码

[ 本帖最后由 xujg 于 2005-11-7 09:14 编辑 ]
作者: wangshim_    时间: 2005-11-07 11:14
上面的哥们,我想问你们2个问题:
1,为什么client断了,server就能知道?,(另client可能是网络断、CTRL+C关闭进程等)
2,可以显示established,和你的多线程有什么关系?

这个完全和网络原理,与操作系统协议栈的处理有关。

1,无论是哪端断,都有可能出现可以显示established的现象。
    1.1 client断,server端不可能立即知道,它只有通过TCP的保活定时器判断连接是否断。
          需要注意的是,socket里recv调用就原理来说应是应用层的网络活动,recv在指定时间内
          没有收到数据,并不代表TCP的连接已断。
    1.2 server断,操作系统连接信息也是定时更新的。可想而知,
          netstat 显示的也不是即时的信息。


有不对的地方,烦请哥们告之。

[ 本帖最后由 wangshim_ 于 2005-11-7 11:19 编辑 ]
作者: xujg    时间: 2005-11-07 11:28
to wangshim_ :
1.我理解的没你这么深,我只是就程序的实现而言,当我select()到该fd可读并且read()的返回是0的时候,就认为该连接是断开了,对于你说的网络断和进程退出都一样.
2.我并没有说established和是否多线程有关系啊,提到多线程,是因为LZ说他是子线程处理连接,并且停在read().
作者: xujg    时间: 2005-11-07 11:30
to wangshim_ :
顺便问一下,如果你写server,你怎么来判断client断开了连接呢?
作者: 柳五随风    时间: 2005-11-07 13:05
加状态控制.如果还要考虑server压力的话,加hearbeat探测(fraom server to client).
作者: xujg    时间: 2005-11-07 13:24
据我所知,心跳一般是由client发给server的吧.来检测闲时长连接是否有效.
作者: wangshim_    时间: 2005-11-07 14:37
client崩溃的现象,叫半打开连接。
心跳机制当然可以用,心跳一般还兼做其它用途,所以一般是client向server主动发送心跳数据。
我想说的是用TCP的保活定时器(keepalive 选项):
他的原理是每隔一定时间向client发送数据,例如“hello,world”,如果能收到ack应答,
就说明对方还处于连接中.他有个优点就是不会影响TCP的正常数据传输。

select等这些东西的应用,说实话,我是对他们的原理不清楚,还请各位赐教。
作者: xujg    时间: 2005-11-07 17:07
呵呵. wangshim_ 兄,很高兴和你讨论这个问题.

先说一些题外话.
我对网络编程不怎么熟悉.接触socket是在几个月前.
我参加的项目中有一个小模块是个消息接收处理模块.所以我边学习边写了一个多线程tcp server.
当时处理server如何知道clinet退出这个问题, 我是参考了网上的资料(具体是哪里的文章我忘记了)并且做了测试后,
用的判断方法是:server时刻关注连接的fd,如果select()到该fd可读但是read()的返回是0的话,那么就认为client主动断开了连接.
具体原理我没有时间,同时也觉得没有必要去了解.在具体开发中,我认为会用select()或许比精通TCP协议更有用,你觉得呢?
现在由于这个帖子,我对其中的细节比较有兴趣了,所以看了一些资料,补充学习了一下.

下面看一下一个连接断开的过程.

为了理解后面的步骤.需要先贴一些代码上来.这里可以先跳过这些代码.
(代码是<Unix Network Programming Volume 1,Third Edition The Sockets Networking API>上直接拷过来的.)


  1. 这是server:

  2. 1 #include    "unp.h"

  3. 2 void
  4. 3 str_echo(int sockfd)
  5. 4 {
  6. 5     ssize_t n;
  7. 6     char    buf[MAXLINE];

  8. 7   again:
  9. 8     while ( (n = read(sockfd, buf, MAXLINE)) > 0)
  10. 9         Writen(sockfd, buf, n);

  11. 10     if (n < 0 && errno == EINTR)
  12. 11         goto again;
  13. 12     else if (n < 0)
  14. 13         err_sys("str_echo: read error");
  15. 14 }

  16. 2 int
  17. 3 main(int argc, char **argv)
  18. 4 {
  19. 5     int     listenfd, connfd;
  20. 6     pid_t   childpid;
  21. 7     socklen_t clilen;
  22. 8     struct sockaddr_in cliaddr, servaddr;

  23. 9     listenfd = Socket (AF_INET, SOCK_STREAM, 0);

  24. 10     bzero(&servaddr, sizeof(servaddr));
  25. 11     servaddr.sin_family = AF_INET;
  26. 12     servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
  27. 13     servaddr.sin_port = htons (SERV_PORT);

  28. 14     Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

  29. 15     Listen(listenfd, LISTENQ);

  30. 16     for ( ; ; )  {
  31. 17         clilen = sizeof(cliaddr);
  32. 18         connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);

  33. 19         if ( (childpid = Fork()) == 0) { /* child process */
  34. 20             Close(listenfd);    /* close listening socket */
  35. 21             str_echo(connfd);   /* process the request */
  36. 22             exit (0);
  37. 23         }
  38. 24         Close(connfd);          /* parent closes connected socket */
  39. 25     }
  40. 26 }
复制代码


  1. 这是client:

  2. 1 #include    "unp.h"

  3. 2 void
  4. 3 str_cli(FILE *fp, int sockfd)
  5. 4 {
  6. 5     char    sendline[MAXLINE], recvline[MAXLINE];

  7. 6     while (Fgets(sendline, MAXLINE, fp) != NULL) {

  8. 7         Writen(sockfd, sendline, strlen (sendline));

  9. 8         if (Readline(sockfd, recvline, MAXLINE) == 0)
  10. 9             err_quit("str_cli: server terminated prematurely");

  11. 10         Fputs(recvline, stdout);
  12. 11     }
  13. 12 }

  14. 2 int
  15. 3 main(int argc, char **argv)
  16. 4 {
  17. 5     int     sockfd;
  18. 6     struct sockaddr_in servaddr;

  19. 7     if (argc != 2)
  20. 8         err_quit("usage: tcpcli <IPaddress>");

  21. 9     sockfd = Socket(AF_INET, SOCK_STREAM, 0);

  22. 10     bzero(&servaddr, sizeof(servaddr));
  23. 11     servaddr.sin_family = AF_INET;
  24. 12     servaddr.sin_port = htons(SERV_PORT);
  25. 13     Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

  26. 14     Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));

  27. 15     str_cli(stdin, sockfd);     /* do it all */

  28. 16     exit(0);
  29. 17 }

  30. Create socket
复制代码


<Unix Network Programming Volume 1,Third Edition The Sockets Networking API.chm>
中关于一个连接正常断开过程的描述:

  1. client连上了server.client输入^D.

  2. 1.When we type our EOF character, fgets returns a null pointer
  3.   and the function str_cli returns.

  4. 2.When str_cli returns to the client main function,
  5.   the latter terminates by calling exit.
  6.   //步骤1和2告诉我们client退出

  7. 3.Part of process termination is the closing of all open descriptors,
  8.   so the client socket is closed by the kernel.
  9.   This sends a FIN to the server, to which the server TCP responds with an ACK.
  10.   //上面这句比较关键,我想这就是server select()的时候可读的原因
  11.   This is the first half of the TCP connection termination sequence.
  12.   At this point, the server socket is in the CLOSE_WAIT state
  13.   and the client socket is in the FIN_WAIT_2 state.

  14. 4.When the server TCP receives the FIN,
  15.   the server child is blocked in a call to readline,
  16.   //server开始读这个文件描述符
  17.   and readline then returns 0.
  18.   //但是缓冲区没有数据可读,所以返回0
  19.   This causes the str_echo function to return to the server child main.

  20. 5.The server child terminates by calling exit.

  21. 6.All open descriptors in the server child are closed.
  22.   The closing of the connected socket by the child causes the final two segments
  23.   of the TCP connection termination to take place: a FIN from the server to the client,
  24.   and an ACK from the client. At this point, the connection is completely terminated.
  25.   The client socket enters the TIME_WAIT state.

  26. 7.Finally, the SIGCHLD signal is sent to the parent when the server child terminates.
  27.   This occurs in this example, but we do not catch the signal in our code,
  28.   and the default action of the signal is to be ignored.
  29.   Thus, the child enters the zombie state. We can verify this with the ps command.
复制代码



以上还不能证明"select()到文件描述符可读但是read()返回0,就说明对方断开连接"是正确的.
因为还有一种情况,如果client发送的就是0字节的内容呢?于是我做了一个简单的测试,
发现write()0字节的时候server根本没有反应,不会select()到fd可读,或者就是说0字节是更本write()不过去的(本来就没有嘛).

还有一种情况,如果client是被kill -9了呢,没来得及close()文件描述符怎么办?
我想这种情况系统会自动close的吧.不知道是否正确.

所以,我的理解是:client断开,server是能够理解知道的,并且是根据"select()到文件描述符可读但是read()返回0"来判断.

对了,select()的功能大致就是告诉我们一个描述符是否已经准备好读,写或异常.

匆匆看了一些资料,没时间细想,还忘各位指正.
作者: xiaofei104    时间: 2005-11-07 22:52
原帖由 wangshim_ 于 2005-11-7 11:14 发表
上面的哥们,我想问你们2个问题:
1,为什么client断了,server就能知道?,(另client可能是网络断、CTRL+C关闭进程等)
2,可以显示established,和你的多线程有什么关系?

这个完全和网络原理,与操作系统 ...


问题1:

在一般的client/server处理模型中,服务器端一般都是在等待客户端的输入,在这个时候如果client端了,server端的socket的read都会返回-1,在这个时候我们就知道client已经断开了,我们可以close这个socket.

问题2:

TCP的确是使用保活定时器来实现keep-alive的,但是这个跟应用程序无关,他的数据根本不会到应用程序。
作者: 柳五随风    时间: 2005-11-07 23:13
除了wang说的部分正确以外,其他全错误.
client端在长连接情况下,如果没有write动作,那么session上没有数据流动,这种情况下,如果client crashed了,那么client 的os没有机会发送FIN报文,server是不知道client出事了,那么对应的server上的sock状态还是established 的,并且会保持这一状态,即使client又从新发起了一个连接请求(server上从新创建一个sockfd).
上面只是给出了其中的一种情况,类似的东西还有.

解决的办法就是对应每一个client,给它生成一个ID,并且将该client ID对应的信息存储在server上,当该client下一次发起请求建立完session之后,检测该client是不是上一次状态还存在,如果是的话,server上主动close上一个session,并清除上一次的status内容.

如果client不能预期什么时候动作的话,server应该定期检查所有status为已经连接,并且长时间没有动作的client的状态,具体的根据情况定,可以是server用heartbeat检测client.也可以是暴力拆除.在暴力拆除的情况下,可能会误伤client,那么client只需要redo一次,但是如果存在交易处理的情况,那么需要考虑rollback等情况.

没那么简单.
作者: xujg    时间: 2005-11-08 08:50
楼上的请注意,我在17楼说的是 normal termination. 而不是 crashes. 请你说个"全错误"的理由.
至于 crashed 的情况, 我一会有时间也学习一下.
作者: xujg    时间: 2005-11-08 09:14
我还是坚持自己的看法,以下可以证明我说的"client 在 normal termination 时 server 可以 select() 到"是正确的.

A socket is ready for reading if any of the following four conditions is true:

a.The number of bytes of data in the socket receive buffer is greater than
   or equal to the current size of the low-water mark for the socket receive buffer.
   A read operation on the socket will not block
   and will return a value greater than 0 (i.e., the data that is ready to be read).
   We can set this low-water mark using the SO_RCVLOWAT socket option.
   It defaults to 1 for TCP and UDP sockets.

b.The read half of the connection is closed (i.e., a TCP connection that has received a FIN).
   A read operation on the socket will not block and will return 0 (i.e., EOF).


c.The socket is a listening socket and the number of completed connections is nonzero.
   An accept on the listening socket will normally not block,
   although we will describe a timing condition in Section 16.6 under
   which the accept can block.

d.A socket error is pending. A read operation on the socket will not block
   and will return an error (–1) with errno set to the specific error condition.
   These pending errors can also be fetched and cleared by calling getsockopt
  and specifying the SO_ERROR socket option.

作者: wangshim_    时间: 2005-11-08 09:42
兄弟们,很高兴大家都能发表真诚的意见。我的意见表达的已很清楚。
xujg,你所说的"可以 select() ",以及:
b.The read half of the connection is closed (i.e., a TCP connection that has received a FIN).
   A read operation on the socket will not block and will return 0 (i.e., EOF).
这段英文说的是半关闭状态,在这种状态下,仍然可以读数据,但不可以写数据。
这个就是shutdown与close的区别,一个可以半关闭,一个是4次握手的全关闭。
作者: xiaofei104    时间: 2005-11-09 20:37
原帖由 柳五随风 于 2005-11-7 23:13 发表
除了wang说的部分正确以外,其他全错误.
client端在长连接情况下,如果没有write动作,那么session上没有数据流动,这种情况下,如果client crashed了,那么client 的os没有机会发送FIN报文,server是不知道client出事了 ...


1.你说的如果client crashed了,如果没有write的话,我觉得这种情况是不存在的,如果仅仅一个TCP连接上了,而且client/server端不进行read,write操作应该是不可能的,如果有read,write操作,在你说的情况下server端肯定知道client端断了,这个时候server断必须要close这个连接,在这种情况下最多是半关闭状态,而不应该是establised状态。
作者: 柳五随风    时间: 2005-11-09 22:50
xiaofei  看看书先.
作者: xiaofei104    时间: 2005-11-10 10:23
原帖由 柳五随风 于 2005-11-9 22:50 发表
xiaofei  看看书先.


没有必要这样!有什么说的不对的敬请指教!
作者: 柳五随风    时间: 2005-11-10 10:54
原帖由 xiaofei104 于 2005-11-10 10:23 发表


没有必要这样!有什么说的不对的敬请指教!



ftp xxx

登录以后啥也别动直接把电源拔了,看看什么情况在说.
作者: xiaofei104    时间: 2005-11-10 23:51
原帖由 柳五随风 于 2005-11-10 10:54 发表



ftp xxx

登录以后啥也别动直接把电源拔了,看看什么情况在说.


我又重新认识了一下这个问题。在这里希望能与大家真诚交流:

1。对于Client / Server模型的应用程序如果Client端在正常情况下断了,如进程关闭,那么服务器端是一定知道的,因为OS会发送FIN。如果Client端应用程序在异常的情况下断了,如:网络断了,机器断电。。。等情况下一般服务器是不知道Client端出了问题的,所以这个时候服务器端的socket还是established状态,在这种情况下服务器socket只有依赖socket timeout机制,或者socket keepalive检查,不过keepalive无法在程序中控制发送频率,默认情况是2个小时。如果要改需要修改操作系统相关参数。

2。这个帖子与我遇到的问题,都是Client在正常关闭(就是Client进程结束的情况。)而非异常关闭的情况下发现服务器的socket还是established状态这一现象表示不理解?所以希望与大家一起讨论。


对于以上两点非常希望与大家交流,如果有什么不对的希望大家指正,不过我更希望大家能够一起来研究一下我所讲到的第二点。

[ 本帖最后由 xiaofei104 于 2005-11-10 23:54 编辑 ]
作者: xujg    时间: 2005-11-11 08:45
我已经一再说明我所说的是"client 在 normal termination"时的情况
可是为什么一直有人要以网络断或者机器断电的情况来说明我的说法是错误的呢
LZ遇到的问题不是在client正常退出的情况吗?

原帖由 zhanghua111 于 2005-11-5 22:07 发表
最近在linux下写了个http代理程序,代理是通过多线程实现的,后来进行压力测试后发现,客户端已经断开了所有的连接,但是在代理的机器上用netstat还能看到ESTABLISHED状态的连接存在,而且一些子线程也没有正常退 ...

[ 本帖最后由 xujg 于 2005-11-11 08:49 编辑 ]
作者: 柳五随风    时间: 2005-11-11 11:34
你怎么知道client是正常退出的?
client程序正常退出不代表client和server的拆会话的4步结束了.看看书再
client退出后,立即查看其socket状态,看看它什么状态.
我觉得很有可能是网络抖动引起的问题,比如线上噪音过大.
作者: xiaofei104    时间: 2005-11-11 11:45
原帖由 柳五随风 于 2005-11-11 11:34 发表
你怎么知道client是正常退出的?
client程序正常退出不代表client和server的拆会话的4步结束了.看看书再
client退出后,立即查看其socket状态,看看它什么状态.
我觉得很有可能是网络抖动引起的问题,比如线上 ...


我不很明确表示了吗?我的正常退出是指进程被用户用窗口右上方的Close按纽关闭,或是被kill pid给干了。在这种情况下操作系统应该给服务器发FIN来结束的。而且我们在这里的问题也很明确了提出对于这种情况下的现象表示不理解?为什么你总是说异常退出的情况。

而且通过同一种方式关闭客户端进程的时候,有时候TCP连接断了,而有时候又没有断。所以对此表示奇怪。希望你不要总是纠缠在没有意义的问题上。

http://bbs.chinaunix.net/viewthr ... ge=1&highlight=

[ 本帖最后由 xiaofei104 于 2005-11-11 11:46 编辑 ]
作者: 柳五随风    时间: 2005-11-11 12:06
原帖由 xiaofei104 于 2005-11-11 11:45 发表


我不很明确表示了吗?我的正常退出是指进程被用户用窗口右上方的Close按纽关闭,或是被kill pid给干了。在这种情况下操作系统应该给服务器发FIN来结束的。而且我们在这里的问题也很明确了提出对于这种情况下的 ...


说明你看不懂我在说什么.完成了4步close,server上能不正常?奇怪的很呢.

在这种情况下操作系统应该给服务器发FIN来结束的。
---失败了怎么办?超过N次失败呢?
如果你的问题发生的很频繁,用类似tcpdump这样的东西把你的packet记录下来,看看到底协议怎么走的(client/server都要).

我在重复一遍,我不认为你说的是对的.至于纠缠,呵呵,恐怕你也是太托大了.
作者: xiaofei104    时间: 2005-11-11 13:26
原帖由 柳五随风 于 2005-11-11 12:06 发表


说明你看不懂我在说什么.完成了4步close,server上能不正常?奇怪的很呢.

在这种情况下操作系统应该给服务器发FIN来结束的。
---失败了怎么办?超过N次失败呢?
如果你的问题发生的很频繁,用类似tcpdump这样 ...


我可以明确的告诉你,在异常的情况下是没有发送FIN的,关键是为什么操作系统在采取同样的方式关闭进程的时候有着不同的反映,有时候发送FIN,有时候却没有发送.
作者: notsureit    时间: 2016-09-20 14:32
我的程序也遇到了这种情况,client都已经关机再次重启了,但是上次的tcp连接仍然在“ESTABLISHED”状态,时间过去一年了,看大家吵架仍然很有意思,问题也没有解决。
        我想解释下上面大家吵来吵去3次4次握手的问题。除了在拔网线和异常掉电以及动态修改本机IP这三种情况外(如有遗漏请指正),client应用程序的关闭,必然会造成server感知到网络断开的,因为程序关闭,操作系统会释放其占用的文件句柄。
        xiaofei104的问题必然不是正常程序关闭造成的,大家首先应该把各自判断的依据弄准确才好。另外,“断开的tcp连接仍然ESTABLISHED”这个问题我还没有解决,打算用client的唯一标识来解决。。。
作者: knull    时间: 2016-09-28 16:17
我也在压力测试的时候碰上过这个问题。
测试场景:同时建立500个连接;client突然断链。会发现,server会有部分连接未断。
在服务端/客户端同时抓包,会发现有些连接,在client抓的包显示已经发送fin包了,但是在server端却没有收到fin。
所以,我觉得,可能是fin包丢失了(因为同时处理这么多tcp_close?)
规避方案:加心跳。心跳,就可以发现连接是否正常。
作者: bskay    时间: 2016-09-28 16:43
正常,linux下,都是要自己发送心跳来检测是否真的连接正常




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2