西部邮币卡交易客户端主动与服务器主动调用客户端断开连接为什么

为什么HTTP标准中 webService 主动会关闭tcp连接?
在http1.1协议中,对于客户端(browser)的一个请求,如果返回Connection:Close,不是告诉客户端让客户端关闭连接,而是服务端之后主动关闭连接,这样的设计方案中,如何解决服务端大量的TIME_WAIT?为什么不设计成让客户端主动关闭连接?
说的都很好,我来补充一下为什么设计为不让客户端主动关闭连接。这确实是历史包袱。原因很简单,早先客户端处理HTTP是单线程的、阻塞的,服务器端发送完信息后客户端要一直等到信息处理完毕、渲染完毕,才能有处理能力来通知服务器处理完成。在当时这个过程可以长达数分钟,而且当时服务器没有能力去承载这么多等待响应的连接(可以用Erlang计算一下这个延迟下需要满足%99.9的可用性需要多么恐怖的硬件)。所以解决方案就是服务器发送完之后就关闭连接。等客户端接收到了所有信息,处理完毕,一看连接也关掉了,此时服务器早已在处理其他连接了。另外这也是为什么有大量TIME_WAIT的原因,相比挂着连接等待客户端关闭,服务器等待确认TCP连接状态要快太多了。说到底就是HTTP协议太老了,虽然高级应用一直在更新,但是这种底层设计很难做出大的改变。这也是为什么Google要弄SPDY来更新HTTP的底层机制。
Server 关闭连接确实是历史原因:HTTP/0.9 协议中 response 是没有 header 的( 参考 Simple-Response 的定义),所以 client 根本无从知道什么时候这个东西结束。如
所说,这里的 FIN 就和读取文件时的 EOF 是一样的作用。想想 UNIX 甚至可以用 read(2) / write(2) 操作 socket fd 就明白这样的意义了。然后回到 RFC 2616:Connection: close 是一个 general-header(
)即:既可以作为 request header 也可以作为 response header。Connection: close 的作用在于"协商(signal)"。14.10 中:HTTP/1.1 defines the "close" connection option for the sender to
signal that the connection will be closed after completion of the
response.即双方都可以关闭。"HTTP: The Definitive Guide" 也是这样表述的。实际上,在 "HTTP: The Definitive Guide" (英文版)p85 中讨论了一模一样的关于 TIME_WAIT 的问题。基本结论是:这个 TIME_WAIT 在 benchmark 的情况下会影响同一台 client 可以发起的请求数量;在实际应用中几乎没有问题。Server 保持 TIME_WAIT 并不是保持 socket,而只是保持一个记录,表示“对应这两个 end-point 的 packet 应该丢弃”,仅此而已。话说这书里上下花了很大篇幅描述了一个相当复杂的关闭逻辑,为的是避免 RST 的出现,倒是有点意思。回头想想:如果是 server 主动关闭连接的情况,只要调用一次 close() 就可以释放连接,剩下的工作由内核 TCP 栈直接进行了处理,整个过程只有一次 syscall;如果是要求 client 关闭,则 server 在写完最后一个 response 之后需要把这个 socket 放入 readable 队列,调用 select / epoll 去等待事件;然后调用一次 read() 才能知道连接已经被关闭,这其中是两次 syscall,多一次用户态程序被激活执行,而且 socket 保持时间更长——到底哪样性能好?
历史遗留吧,HTTP最早(0.9或更早)只有短连接,服务器关闭连接表示数据发送完毕。请懂行的说说为啥后来一直没有甩掉这个包袱吧?
根据有限的 TCP 和 HTTP 知识说明一下。TCP 的 FIN 标记相当于“读到文件尾”这一信号。客户端在收到服务器端发来的 FIN 标记就知道数据已经发完,可以进一步处理 HTTP Response 报文。如果换客户端自己来计数也不是不可行,但要考虑到有一些 HTTP Response 报文可能缺少 Content-Length Header (该首部不是强制性要求的)。另外,HTTP 1.1 要求默认使用 Keep-Alive,以便复用 TCP 连接(即长连接,不设置 Connection Header 就会有此效果),服务器端不会主动关闭连接,此时要求客户端自己进行报文长度计数,是否关闭连接由客户端控制。如果通信过程出现异常,服务器端会返回 RST 标记,强制断开虚连接。解决 TIME_WAIT 的办法之一是修改内核参数将 2MSL 调小(影响整个系统,范围过大,不推荐)。====有个问题,所谓“服务器端大量的 TIME_WAIT”会有什么影响么?有点迷糊了。
服务端资源是有限的,所以服务端要主动关闭连接。
timewait 问题,设置 tw_reuse 即可。
已有帐号?
无法登录?
社交帐号登录6224人阅读
Winform(C#)
现象:服务器端等待客户断连接,当socket连接建立后,如果客户端异常断开,服务器会抛出异常,从而导致程序运行中断目标:希望服务器一直等待连接,客户端中断后程序不退出,而客户端重新恢复后可以继续保持连接代码:public class Receive{public static byte[] buffer= new byte[1024];public static ManualResetEvent socketEvent = new ManualResetEvent(false);public static Socket sListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);public static Socket handler =public static string ClientBroken = &An connection was forcibly closed by the remote host&;public static void receive(){try{Console.WriteLine(&Main ThreadID:& + AppDomain.GetCurrentThreadId());byte[] bytes = new byte[1024];IPAddress ipAddr = IPAddress.Parse(&127.0.0.1&);int Port = 10001;IPEndPoint EPServer = new IPEndPoint(ipAddr, Port);//Binding a socketsListener.Bind(EPServer);//Start listeningsListener.Listen(10);while(true){if (handler==null){//first must make a connectConsole.WriteLine(&waiting for a connection...&);//asychronous function for accepting connectionssListener.BeginAccept(new AsyncCallback(AcceptCallback), sListener);socketEvent.WaitOne();handler.BeginReceive(buffer,0,buffer.Length,0,new AsyncCallback(ReceiveCallback),handler);socketEvent.WaitOne();}else{Console.WriteLine(&waiting next message...&);socketEvent.Reset();handler.BeginReceive(buffer,0,buffer.Length,0,new AsyncCallback(ReceiveCallback),handler);socketEvent.WaitOne();}}Console.ReadLine();}catch (Exception e){Console.WriteLine(e.ToString());}Console.ReadLine();}public static void AcceptCallback(IAsyncResult ar){try{Console.WriteLine(&AcceptCallback Thread ID:& + AppDomain.GetCurrentThreadId());Socket listener = (Socket)ar.AsyncS//new sockethandler = listener.EndAccept(ar);handler.BeginReceive(buffer,0,buffer.Length,0,new AsyncCallback(ReceiveCallback),handler);}catch (Exception e){Console.WriteLine(e.ToString());}}public static void ReceiveCallback(IAsyncResult ar){string err_message=try{Console.WriteLine(&ReceiveCallback Thread ID:& + AppDomain.GetCurrentThreadId());string content = String.Ehandler = (Socket)ar.AsyncSint bytesRead = handler.EndReceive(ar);//if there is some data...if (bytesRead&0){//append it to the main stringcontent += Encoding.ASCII.GetString(buffer,0,bytesRead);//if we encounter the end of message characterif (content.IndexOf((char)3)& -1 || content.IndexOf((char)16)&-1){Console.WriteLine(&Read &+content.Length+& bytes from socket. /n Data:&+content);socketEvent.Set();}else{//otherwise receive the remaining datahandler.BeginReceive(buffer,0,buffer.Length,0,new AsyncCallback(ReceiveCallback),handler);}}}catch(Exception e){err_message = e.Mif (err_message.IndexOf(&An existing connection was forcibly closed by the remote host&)& -1){Console.WriteLine(&An existing connection was forcibly closed by the remote host&);//handler.Shutdown(SocketShutdown.Both);//handler.Close();Console.WriteLine(&waiting for a connection...&);//asychronous function for accepting connectionssListener.BeginAccept( new AsyncCallback(AcceptCallback), sListener);}else{Console.WriteLine(e.ToString());}}}}说明:关键在于最后这段的异常处理,接收中断后,服务器端重新等待接收。现象:客户端与服务器连接,当socket连接建立后,如果服务器端异常断开,客户端会抛出异常,从而导致程序运行中断目标:希望客户端出现提示,服务器端中断后程序不退出,而服务器端重新恢复后可以继续保持连接代码:public class AsyncComm{public static string theResponse = &&;public static byte[] buffer = new byte[1024];public static ManualResetEvent socketEvent = new ManualResetEvent(false);public static Socket sClient= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);public static IPEndPoint EPServer = new IPEndPoint(IPAddress.Parse(&127.0.0.1&), 10001);public static void send(string data){byte[] byteData=byteData = Encoding.ASCII.GetBytes(data);try{if (!sClient.Connected){Console.WriteLine(System.DateTime.Now.ToString(&yyyy-MM-dd HH:mm:ss:ffff&)+& &+&Connect begining......&);sClient.BeginConnect(EPServer, new AsyncCallback(ConnectCallback),sClient);socketEvent.WaitOne();}sClient.BeginSend(byteData,0,byteData.Length,0,new AsyncCallback(SendCallback),sClient);socketEvent.WaitOne();}catch (Exception e){Console.WriteLine(&Server side is broken...&);socketEvent.Reset();}}&&&&&&&& public static void ConnectCallback(IAsyncResult ar){try{Thread thr = Thread.CurrentTConsole.WriteLine(&ConnectCallback Thread State:& + AppDomain.GetCurrentThreadId());Socket sClient = (Socket)ar.AsyncSsClient.EndConnect(ar);Console.WriteLine(&Socket connected to & + sClient.RemoteEndPoint.ToString());socketEvent.Set();}catch (Exception ex){Console.WriteLine(System.DateTime.Now.ToString(&yyyy-MM-dd HH:mm:ss:ffff&)+&||&+AppDomain.GetCurrentThreadId()+&||3--Level 3 Server connection is broken, waiting for Level 3 Server connection......&);sClient= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);socketEvent.Set();}}receive函数相同,可以参照写出说明:在每次发送或接收时检测当前socket是否连接,如果没有连接,就启动连接,并阻塞线程等待ConnectCallback的返回&&
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:52113次
排名:千里之外
原创:15篇
(1)(1)(2)(2)(1)(1)(1)(5)(1)(10)4980人阅读
全部(26)
问题背景:
&&&&&&& 最近做C/S结构的程序,项目中需要开发TCP服务器端,需要能够接收多个客户端的连接请求。开发完成后,测试过程中出现了如题问题。
&问题描述:
&&&&&&& 启动服务器,开启多个客户端,建立连接通讯,一切正常。关闭客户端(一个或多个),此时用netstat命令查看网络状态,发现所关闭的客户端的连接没有完全释放,而是处于CLOSE_WAIT状态。
解决方法:
&&&&&&& MSDN中获取当前的连接状态的说明如下:
&& & & &Connected 属性的值反映最近操作时的连接状态。如果您需要确定连接的当前状态,请进行非阻止、零字节的 Send 调用。如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;否则,该套接字不再处于连接状态。
&& & & &经测试测方法并不能准确的获取到当前连接的状态。(环境:windows xp sp3,.Net framework 3.5)。测试发现每次关闭客户端后异步接受的返回值都零字节(我使用的是异步接收数据),因此就依据这一条件判断连接是否断开,即接收的字节为零则断开连接。经过测试此种方式确实可以对客户程序的退出作出及时的响应,本以为问题到此已经解决了,但是对另一种客户端断开方式——网线断开,还是不能及时地作出响应。搜索相关问题,找到参考文章()。,有如下描述:
&&&&&&&&【引用参考】我们知道,TCP有一个连接检测机制,就是如果在指定的时间内(一般为2个小时)没有数据传送,会给对端发送一个Keep-Alive数据报,使用的序列号是曾经发出的最后一个报文的最后一个字节的序列号,对端如果收到这个数据,回送一个TCP的ACK,确认这个字节已经收到,这样就知道此连接没有被断开。如果一段时间没有收到对方的响应,会进行重试,重试几次后,向对端发一个reset,然后将连接断掉。&
&&在Windows中,第一次探测是在最后一次数据发送的两个小时,然后每隔1秒探测一次,一共探测5次,如果5次都没有收到回应的话,就会断开这个连接。但两个小时对于我们的项目来说显然太长了。我们必须缩短这个时间。那么我们该如何做呢?我要利用Socket类的IOControl()函数。我们来看看这个函数能干些什么:&
&&使用 IOControlCode 枚举指定控制代码,为 Socket 设置低级操作模式。 【引用参考】
&& & & &MSDN中IOControlCode的说明:为
设置低级别操作模式。两个重载如下:
&&&&&&&&1、IOControl(Int32, array&Byte&[]()[], array&Byte&[]()[])&
&&&&&&& 2、IOControl(IOControlCode, array&Byte&[]()[], array&Byte&[]()[])
&&&&&&& 我们采用第二种重载。
&&&&&&& 首先需要弄清参数的意义。
&&&&&&& 【引用参考】
&&&&&&& 在C++里它是一个结构体。我们来看看这个结构体:
&&&&&&& struct tcp_keepalive
&&&&&&&&&&& u_long& //是否启用Keep-Alive
&&&&&&&&&&&&u_long& //多长时间后开始第一次探测(单位:毫秒)
&&&&&&&&&&&&u_long& //探测时间间隔(单位:毫秒)
&&&&&&& };
&&&&&&&在C#中,我们直接用一个Byte数组传递给函数:
&&&&&&& uint dummy = 0;
&&&&&&& byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
&&&&&&& BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);//是否启用Keep-Alive
&&&&&&& BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy));//多长时间开始第一次探测
&&&&&&& BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);//探测时间间隔
&&&&&&& 【引用参考】
&&&&&&& 结合以上两种种方法,服务器端对网络连接的断开都能作出及时的响应,至此问题解决。
&&&&&&& 如果其中有描述不清楚或不正确的地方,望不吝赐教。
1、/msoft//430.shtml
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:50432次
排名:千里之外
原创:17篇
转载:11篇
(1)(2)(2)(1)(2)(2)(1)(1)(1)(3)(1)(4)(2)(3)(2)服务器端与客户端建立了TCP连接, 但是 Client 并没有close, server端会主动断掉TCP连接么?_百度知道java网络编程中,对于客户端和服务器的tcp连接,如果客户端异常断开连接,服务器端如何获知,有什么方法?_百度知道

我要回帖

更多关于 tcp 客户端主动断开 的文章

 

随机推荐