如何判斷一個tcp空連接(50分)

M

melice

Unregistered / Unconfirmed
GUEST, unregistred user!
rt , 一個長時間沒有通訊的連接,經常會因為某種原因斷開了,但是並不一定會觸發連接斷開,
這種空連接怎麼判斷出來並斷掉.
 
用一个timer控件,每隔30秒判断 tcpclient.connected;

我用的是idtcpclient
 
你用的什么网络组件?
 
TCP连线的中断必须在下次的Read/Write时才会触发,
所以较佳的方式就如同楼上所说的用个计时器来判断.
 
不会呀,一般只要断开,无论什么原因都能够触发断开事件的(假如你用事件IO模型)。不过
TCP一般在一段时间没有数据交换后会自动断开,如果需要保持连接,则每隔一段时间会发
送一个类似“我还活着”这样的信息。这个信息不由用户控制的。
用TTimer是臭手常用的方法。GetSocketOpt函数带SO_CONNECT_TIME参数会返回连接的时
间。只要是Socket应用一定会有某种方法进行阻塞或者循环的。在阻塞或者循环的过程中
检测Socket连接时间最方便了。Microsoft推荐这种做法。
 
怎么会!如果WSASelectEvent中加了FD_CLOSE就一定会检测到断开,无论是寄生虫户端断
开还是用CloseSocket主动断开。只要是面向连接的Socket就一定会。因为面向连接的
Socket不象UDP那样,断开就完事了,而TCP即使断开也需要完成很多的动作。
 
to 爱元元的哥哥 : 用的是经典的ServerSocket
to barton : 呃....实际上当连接数到5000以上的时候,就经常出现空链接的了. 其特征和SnoopyChen说的一样, 对该链接读写的时候就会立刻断掉.
to wwolf : 服务器上的链接是保持在2w个左右的, 现在我用的是200ms的timer来轮询,但是对所有链接轮询一遍的时间有点久..:<
 
这是Jon C. Snader的著作 [Effective TCP/IP Programming --
44 Tips to Improve Your Network Programs] 其中一个Tip的开头。
作者网站: http://www.netcom.com/~jsnader

(我看的是繁体版 林洙如 译, 当然首选的教课书应是Stevens的UNIX
NETWORK PROGRAMMING 2nd系列的书, 可惜他已不在人世!)
---------------------------------------------------------------
TIP 10:记得,TCP/IP不是一直发出探测讯息的通讯协定

熟悉其他网路技术的网路工程师在刚开始接触TCP/IP通讯协定时, 一
旦他们发现TCP 不能立即对应用程式提供连结中断通知, 往往会觉得疑
惑甚至是失望。某些人甚至就下了TCP 不适合使用在应用程式间通讯的
结论。在这个TIP中我们将讨为何TCP没有提供这种通知的原因, 这种做
法的优缺点在那里, 以及应用程式设计师应采取何种方法, 来侦测连结
是否已经中断。

如同我们在TIP 9 中所看到的, 网路中断或系统当机, 可能使得两端
的应用程式在错误发生时, 无法立即被侦测到, 也无法继续传递讯息。
而传送端的应用程式, 直到TCP 放弃重传之前, 它不会发现该连结已经
中断。在耗费相当可观的时间之后, 它才会发现连结已经中断, 因为在
BSD 系统中, TCP 大约九分钟之后才会放弃重传。而且, [red]假如这个应用
程式并没有处在传送资料的状态下, 它可能永远也不会发现连结中断了[/red]
...

设计TCP 时不提供连结中断的立即通知, 其最重要的原因即是它主要
的设计目的: 当面对网路的瘫痪时, 它要具备继续维持通讯的能力。TCP
是(美国)国防部所支持的研究计划的产物, 它的设计理念是, 即使它面
对的是因战争或重大天然灾害而造成的网路瘫痪, 它所提供的网路通讯
协定也要能维持电脑之间可靠的通讯。网路中断常常只是暂时性的, 或
者路由器可以为连结找到一条(不同的)路径。藉由容忍暂时的连结中断,
TCP 甚至能够在相对两端的应用程式都不知道的情况下度过网路中断的
危机。
---------------------------------------------------------------

至于为何很多人经验上或认为网路中断时可以立即得知, 其实这就要了
解TCP/IP的原理, 比方说你是以拨接PPP 连上线, 因为不是固定IP, 所
以即使断线后重新连上Internet, 但你的IP已经变更了, 这时就算两端
的程式未曾中止, 但再也连不上了。如果你是使用固定IP的话, 可以试
试看将你的网路线拔掉一会再接上, 这时你的程式还是可正常接收, 并
不会中断。
 
to melice:你的连接数能够达到20000个,一定用了完成端口。我测试的结果是:如果连接
断开,GetQueuedCompletionStatus要么检测是False,要么Bytes=0,两种情况下都说明已
断开。另外,完成端口的线程中你怎么使用Timer?搞不懂。如果还需要专门的线程或定时
器检测连接是否断开岂不是资源的浪费?
只有一种情况需要使用轮询:用AcceptEx函数时为防止“拒绝服务”攻击而轮询已经守候
的连接,这些连接的数量很少,一般8~16个。而且间隔时间不需要很短,1~30秒都可以。
至于SnoopyChen所说“网路线拔掉一会再接上”并不会中断那是因为还没有到超时的时间。
你试试拔掉10分钟试。一定会自动触发断开事件。那本事根本在胡说。MS的资料应该更权
威一些吧。
 
to SnoopyChen : 或许以前的设计是按你所说的,但是按照我以前做的试验, 两个固定ip之间的一个正常的tcp链接,如果我把网线拔掉,最慢在一秒以后就会触发Error, 即使我把网线再插回去,也已经是没有意义的了.
 
to barton : iocp的优势应该是在用户接入的速度方面,经过我的测试,现在使用的模式,客户端接入的时间约为3-4秒,这个是用户可以忍受的范围之内。
btw,iocp与连接数好像没有直接关系的吧?
 
to melice:到现在为止,还只有iocp这种IO模式能够承受20000个连接。你可以查查从前的
贴子。iocp并没有速度方面的优势,只是一方面能够承受较多的连接数,另一方面更好地
利用多个CPU的效能。客户端连接时间与io模式才没有什么直接关系。

我查了关于SO_KEEPALIVE的资料,Win98和Win2000/NT的处理方式略有不同。两者都会按
某个固定间隔时间向另一方发送Keep Alive消息,前者的间隔时间查询:
/HKEY_LOCAL_MACHINE/System/CurrentControlSet/Services/Vxd/MSTCP;
后者的间隔时间查询:
/HKEY_LOCAL_MACHINE/System/CurrentControlSet/Services/TCPIP/Parameters。
如此可见,一旦通过SO_KEEPALIVE参数修改了间隔时间,整个TCPIP体系都会随之变化。不
过,Win2000可以例外,通过SIO_KEEPALICE_VALS这个控制命令可以对某一个套接字修改间
隔时间。
这个间隔时间最多2个小时(算算多少个毫秒),最少为0。当为零的时候,楼主说的现象可
能会发生。
 
原来才搞清楚,你用的是Delphi的ScktComp单元提供的ServerSocket。这个部件不可能承
受20000个连接。兄弟,ServerSocket那可用的是线程阻塞式的,20000个连接意味着20000
个线程。2000个线程都会让我瞠目结舌!那你说的现象可能根本就不是因为Socket的原因,
而是你所谓的连接根本就不存在!
 
参考:http://www.delphibbs.com/delphibbs/dispq.asp?lid=1666178
我认为如果达到2000个线程,CPU将会花80%的时间处理线程场景切换。
 
ServerSocket 能支持 5000 个以上的可靠的连接?不敢想象啊。我怎么就做不到呢?要命。
轮询式地发“我还活着”信息,在这样大的每线程式的连接数量下也是没有用的吧。
“iocp 的优势应该是在用户接入的速度方面”,这好象也与事实不符吧,接入速度好象还是
每线程式的快吧。
TO barton ,每线程式的连接,不考虑网络的因素,800 个都是困难的(有机器内存大小的因素)。
 
小雨哥,你理解有误,我的意思是,“我还活着”这样的信息是由系统来控制的,用户不
需要干预的。
有关线程阻塞完全同意你的看法。
 
“我还活着”这样的消息根本没有实用性,间隔时间最短不能少与2小时,
而且TCP有的时候Client非法断开,服务器是收不到断开通知的.在Internet
上测试才有效,
 
to 张无忌:
说实话,有不有实用性并不是你能够控制的。我相信设计这一功能的人比你更了解TCP,他
不会设计这么个完全没有道理的功能。
我可以肯定地讲,在一定的时间范围内,肯定是可以收到断开信息的,虽然有时候并不是
马上收到。TCP断开是需要“Graceful”的,这意味着系统会瞒着你偷偷向对方发送很多
用于“传输控制”的内容。要不然怎么会叫“传输控制协议”。
我根本不相信“而且TCP有的时候Client非法断开,服务器是收不到断开通知的”这样的结
论。
 
我的理解 Keep Alive 的含义在 TCP 中是让服务端有义务转入发送 keep-alive packets
状态,在 Windows Socket 中却是指客户端在向该连接发动请求时,可以收到 WSAENetReset
错误信息,表明请求的连接已经被服务端否决。
在 ServerSocket 情况下,没有利用系统特征判断连接是否是可靠存在的手段,就是因为
他不是总能收到客户断开的通知的缘故,判断是否连接存在,还是要自己发“我还活着”
信号,并且必须保证服务管理的连接在 500 以下,多于 500 个连接,就应该考虑增加服
务级数,或者考虑安排每次连接是可以被处理后断开这样的模式,不知道对否。
 

首先我认为长时间保持空连接是没有任何意义的,在实际高负载的系统中保持客户的空连接是一个大笑话,另外 Borland 的 ServerSocket 只是一种很简单的写法,所以他很多控制处理都没有写。
要判断是不是一个空连接其实可以很简单的处理,采用 Select 方法就可以处理,当用户异常断开时,此时需要在服务器端采用一下就可以知道用户已经断开,本线程现在可以挂起,等待下一个请求时再触发。
另外是不是一定要为几千个连接来开开几千个线程?我认为没有必要(一个极端的情况:当用户的请求已经是要花费很长一段时间才能处理完毕的情况下,例如 FTP ,这时才需要为每个用户请求创建一个线程),我现在我的服务器端,开啦 10 个线程做线程池,可以每分钟处理 2 万多个用户请求(根据机器性能、请求数据量大小和网络带宽不同,其负载能力不同)。
另外完成端口,他在处理用户请求的时候使用啦更小的内核处理对象:纤程;这是一个用户态空间处理的类似线程一样的东东。为了达到高性能,我们在线程同步处理上要尽可能使用用户态模式下的同步处理,并且尽量减少用户态和内核态的现场切换(当然还有一些其他要素),这样我们的系统性能会提升非常大。

 
顶部