I'm having a hard time figuring out while a HttpWebRequest in .NET 4.0 creates a socket connection for each request but isn't able to close the socket afterwards. When I execute e.g 50 HttpWebRequests I see 50 TCP socket connections in the WAIT state in netstat.
I already reduced the code to a minimum:
Dim webReq As HttpWebRequest
Dim webRes As HttpWebResponse
Dim webStream As IO.StreamReader
Dim _answer As String
webReq = System.Net.HttpWebRe开发者_运维问答quest.Create(TextBox1.Text)
webReq.Timeout = 10000
webReq.Method = WebRequestMethods.Http.Get
webRes = webReq.GetResponse
webStream = New IO.StreamReader(webRes.GetResponseStream(), System.Text.Encoding.ASCII())
_answer = webStream.ReadToEnd
RichTextBox1.Text = _answer
webRes.Close()
webRes = Nothing
webReq = Nothing
Any idea, hint is appreciated!
Thanks in advance
Chris
after I've gained some more insight on this topic, I'm able to give an answer to myself now.
Whenever you open a socket and close it, it enters the "TIME-WAIT" status before being closed completely. This state should prevent that a following tcp connection receives delayed tcp-packets late on. I was dealing with an application that posts several thousand CGI requests to a server. Problem was the server using HTTP/1.0 which means that every request opened a new socket and closed it immediately after exchanging the data. After a while thousands of tcp connections where shown in netstat within the "TIME-WAIT" status. The sockets, or to be more precise ports, became exhausted. Windows was not giving the application new sockets for new CGI requests. After a while all the TIME-WAIT sockets were closed and the application could continue to communicate. This problem was originated in the HTTP/1.0 nature of the server.
There are two "fixes" for this problem from a Windows point of view. By tweaking the REGISTRY you can allow Windows to manage more then the default 5000 tcp connections (I've read a good upper limit can be 20.000). The other option is to reduce the TIME-WAIT time itself. This can be also done by tweaking the REGISTRY. Both options were no real solution to our massive socket-exhaustion-problem.
In the final solution we've used a TCP socket option called "SO-LINGER". Setting this option while creating the port allows to skip the TIME-WAIT state of a TCP socket. Please keep in mind that this state exists for a reason! Skipping it was one of the last options and suits our needs because we are transmitting a couple bytes over the socket. Before using this option, consider possible impacts.
The project was developed in VB .NET 4.0. The code I've used to create the socket is posted below:
Private _plcAddress As String
Private _plcSocket As Socket
Private _endPoint As IPEndPoint
...
Dim myOpts As New LingerOption(True, 0)
Dim ipAddress As IPAddress = ipAddress.Parse(plcAddress)
_plcAddress = plcAddress
_plcSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP)
_plcSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, myOpts)
_endPoint = New IPEndPoint(IPAddress, 80)
...
Do you mean 'TIME_WAIT'? If so, do your 50 requests, go for a coffee, come back to your box, recheck with netstat.
Closing a TCP socket performs the terminate handshake and queues the socket object for release. The socket is not actually released for some minutes by TCP design - some packets may still be on their way by slow routes even after a successful connection termination & so the socket must not be reallocated to another connection until any such leftovers have died.
Rgds, Martin
精彩评论