我有一个HTTP服务器和客户端(它们都是我的代码,C#,服务器上的HttpListener和客户端上的HttpWebrequest)。
每个客户端每分钟向服务器发出大约6个HTTP请求(如果一切正常)。每个服务器最多可以有10000个客户端。服务器应在不到1秒的时间内响应。服务器逻辑很简单(没有CPU问题)。最多的代码是异步的。
在某些环境(内联网)中,一切都可以正常工作。
但是在某些Intranet环境中,大约3个POST HTTP Web请求中的1个挂起。
该问题在VMware(Win 8.1 Professional,6.3.9600 build 9600 .net 4.7.1)的单客户端计算机上明显体现
我无法在另一台计算机上复制它,也无法将该VM移至另一网络环境。因此,我需要获取一些更详细的信息。
问题在下面详细说明。就像
中所述Async TCP System.Net.Socket send (Begin/End Send) not actually sending anything several years ago.
我已经按照Microsoft的建议从客户端和服务器那里获取了WireShark以及详细的System.Net日志。
<source name="LowLevelDesign" switchValue="Verbose">
<source name="System.Net.Http" switchValue="Verbose">
<source name="System.Net.HttpListener" switchValue="Verbose">
<source name="System.Net" switchValue="Verbose">
<source name="System.Net.Sockets" switchValue="Verbose">
来自同一套接字上客户端的多个POST HttpWebRequest可以正常工作,即日志显示请求之间的客户端端口和套接字ID相同。
我在服务器和客户端上都在Wireshark中看到所有TCP数据包都正常(服务器上的唯一警告是校验和:0xd28c不正确,应该是0xb54c(可能是由于“ TCP校验和卸载”引起的?)。
服务器对所有请求的响应大大少于1秒。
然后,在成功请求3或4个请求之后,客户端尝试发送下一个请求。
但是Wireshark中没有TCP数据包(在服务器或客户端)。由于没有看到请求,因此服务器没有任何答案。
我的代码检测到超时(10秒)而没有答案,并中止了HttpWebRequest。
然后,相同的(新的)请求在其他新的套接字(即新的客户端端口)上也可以很好地工作。但是在3-6次请求后,问题又重复了。
没有长度大于1500的消息。被挂起的请求也是短消息(标头<100字节,POST请求流数据<200字节,响应<400字节)。我看到OK和Hanged请求之间没有区别,除了OK是第一个,而Hanged是第二个,并带有100个继续。所有其他请求都没有请求数据(即request content-length == 0)。我看到带有100个继续的第二个请求始终在该环境中挂起。
由于我看到服务器在2分钟后将[RST,ACK]发送到旧套接字(旧客户端端口),因此旧连接未正确处理。而且我不知道如何优雅地关闭它。
...
System.Net.Sockets Verbose: 0 : [6420] Data from Socket#11429296::PostCompletion
DateTime=2019-06-24T06:43:08.7370581Z
...
System.Net.Sockets Verbose: 0 : [6420] 000000A0 : 35 0D 0A 45 78 70 65 63-74 3A 20 31 30 30 2D 63 : 5..Expect: 100-c
DateTime=2019-06-24T06:43:08.7410625Z
System.Net.Sockets Verbose: 0 : [6420] Socket#11429296::EndSend(OverlappedAsyncResult#13804354)
DateTime=2019-06-24T06:43:08.7420738Z
System.Net.Sockets Verbose: 0 : [6420] Exiting Socket#11429296::EndSend() -> Int32#187
DateTime=2019-06-24T06:43:08.7420738Z
System.Net.Sockets Verbose: 0 : [6420] Socket#11429296::UnsafeBeginReceive()
DateTime=2019-06-24T06:43:08.7420738Z
System.Net.Sockets Verbose: 0 : [6420] Exiting Socket#11429296::UnsafeBeginReceive() -> OverlappedAsyncResult#47962264
DateTime=2019-06-24T06:43:08.7431561Z
System.Net Verbose: 0 : [5896] HttpWebRequest#52253787::EndGetRequestStream()
DateTime=2019-06-24T06:43:09.1071980Z
System.Net Verbose: 0 : [5896] Exiting HttpWebRequest#52253787::EndGetRequestStream() -> ConnectStream#17987329
DateTime=2019-06-24T06:43:09.1081881Z
System.Net Verbose: 0 : [5896] ConnectStream#17987329::BeginWrite()
DateTime=2019-06-24T06:43:09.1081881Z
System.Net Verbose: 0 : [5896] Data from ConnectStream#17987329::BeginWrite
DateTime=2019-06-24T06:43:09.1091858Z
System.Net Verbose: 0 : [5896] 00000000 : 7B 22 43 6F 6E 6E 65 63-74 69 6F 6E 73 22 3A 7B : {"Connections":{
DateTime=2019-06-24T06:43:09.1091858Z
...
System.Net.Sockets Verbose: 0 : [5896] Socket#11429296::BeginSend()
DateTime=2019-06-24T06:43:09.1140970Z
System.Net.Sockets Verbose: 0 : [5896] Exiting Socket#11429296::BeginSend() -> OverlappedAsyncResult#60375305
DateTime=2019-06-24T06:43:09.1151910Z
System.Net Verbose: 0 : [5896] Exiting ConnectStream#17987329::BeginWrite() -> NestedSingleAsyncResult#46228029
DateTime=2019-06-24T06:43:09.1160992Z
System.Net.Sockets Verbose: 0 : [6420] Data from Socket#11429296::PostCompletion
DateTime=2019-06-24T06:43:09.1180991Z
System.Net.Sockets Verbose: 0 : [6420] 00000000 : 7B 22 43 6F 6E 6E 65 63-74 69 6F 6E 73 22 3A 7B : {"Connections":{
DateTime=2019-06-24T06:43:09.1180991Z
...
System.Net.Sockets Verbose: 0 : [6420] Socket#11429296::EndSend(OverlappedAsyncResult#60375305)
DateTime=2019-06-24T06:43:09.1212220Z
System.Net.Sockets Verbose: 0 : [6420] Exiting Socket#11429296::EndSend() -> Int32#125
DateTime=2019-06-24T06:43:09.1212220Z
System.Net Verbose: 0 : [6420] ConnectStream#17987329::EndWrite()
DateTime=2019-06-24T06:43:09.1212220Z
System.Net Verbose: 0 : [6420] Exiting ConnectStream#17987329::EndWrite()
DateTime=2019-06-24T06:43:09.1222229Z
System.Net Verbose: 0 : [6420] ConnectStream#17987329::Close()
DateTime=2019-06-24T06:43:09.1222229Z
System.Net Verbose: 0 : [6420] Exiting ConnectStream#17987329::Close()
DateTime=2019-06-24T06:43:09.1232215Z
System.Net Verbose: 0 : [7368] HttpWebRequest#52253787::BeginGetResponse()
DateTime=2019-06-24T06:43:09.1232215Z
System.Net Verbose: 0 : [7368] Exiting HttpWebRequest#52253787::BeginGetResponse() -> ContextAwareResult#13009416
DateTime=2019-06-24T06:43:09.1241884Z
System.Net Verbose: 0 : [7368] HttpWebRequest#52253787::Abort()
DateTime=2019-06-24T06:43:18.7330583Z
Wireshark:
Protocol Length Info
TCP 66 56916 → 33444 [SYN] Seq=0 Win=8192 Len=0 MSS=1432 WS=256 SACK_PERM=1
TCP 66 33444 → 56916 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1404 WS=256 SACK_PERM=1
TCP 54 56916 → 33444 [ACK] Seq=1 Ack=1 Win=65792 Len=0
HTTP 248 POST /Service_v2/GetServerInformation/ HTTP/1.1
TCP 60 33444 → 56916 [ACK] Seq=1 Ack=195 Win=65792 Len=0
HTTP 438 HTTP/1.1 200 OK (text/plain)
TCP 54 56916 → 33444 [ACK] Seq=195 Ack=385 Win=65536 Len=0
HTTP 220 POST /Service_v2/GetServerLicense/ HTTP/1.1
TCP 60 33444 → 56916 [ACK] Seq=385 Ack=361 Win=65792 Len=0
HTTP 1252 HTTP/1.1 200 OK (text/plain)
TCP 54 56916 → 33444 [ACK] Seq=361 Ack=1583 Win=65792 Len=0
HTTP 220 POST /Service_v2/GetSecondMessage/ HTTP/1.1
TCP 60 33444 → 56916 [ACK] Seq=1583 Ack=527 Win=65536 Len=0
HTTP 858 HTTP/1.1 200 OK (text/plain)
HTTP 265 POST /Service_v2/GetMainMessage/?messageid=10d5d406-634e-4b65-9d99-f614e8b8398b HTTP/1.1
TCP 60 33444 → 56916 [ACK] Seq=2387 Ack=738 Win=65280 Len=0
HTTP 836 HTTP/1.1 200 OK (text/plain)
TCP 241 56916 → 33444 [PSH, ACK] Seq=738 Ack=3169 Win=65792 Len=187 [TCP segment of a reassembled PDU]
TCP 60 33444 → 56916 [ACK] Seq=3169 Ack=925 Win=65024 Len=0
HTTP 79 HTTP/1.1 100 Continue
HTTP 181 POST /Service_v2/ProcessMessage/ HTTP/1.1 (application/raw)
TCP 60 33444 → 56916 [ACK] Seq=3194 Ack=1052 Win=65024 Len=0
HTTP 372 HTTP/1.1 200 OK (text/plain)
TCP 54 56916 → 33444 [ACK] Seq=1052 Ack=3512 Win=65536 Len=0
HTTP 220 POST /Service_v2/GetSecondMessage/ HTTP/1.1
TCP 60 33444 → 56916 [ACK] Seq=3512 Ack=1218 Win=64768 Len=0
HTTP 882 HTTP/1.1 200 OK (text/plain)
TCP 54 56916 → 33444 [ACK] Seq=1218 Ack=4340 Win=64768 Len=0
Here I try to make new POST /Service_v2/ProcessMessage/ HTTP/1.1 (application/raw) but there are NO data in WireShark
I see only next line ([RST, ACK]) after 2 minutes, no [FIN], no [ASK], no [PSH]
TCP 60 33444 → 56916 [RST, ACK] Seq=4340 Ack=1218 Win=0 Len=0
源代码:
public ServerHttpRequest(string methodSuffix, NameValueCollection requestParams = null, string requestBody = null)
{
if (methodSuffix == null)
throw new AggregateException(nameof(methodSuffix));
_methodSuffix = methodSuffix;
_requestParams = requestParams;
_requestBody = requestBody;
}
public async Task<string> SendRequest()
{
var sendRequestTask = Send();
if (await Task.WhenAny(sendRequestTask, Task.Delay(TimeSpan.FromSeconds(Configuration.ServerTimeout))) == sendRequestTask)
return await sendRequestTask.ConfigureAwait(false);
ThreadPool.QueueUserWorkItem(this.Abort);
throw new TimeoutException("HttpRequest timeout exceeded. Probably having problems connecting to the server.");
}
private void Abort(object obj)
{
try
{
_httpRequest?.Abort();
}
catch (Exception ex)
{
Log(ex);
}
}
private HttpWebRequest CreateRequest(string methodSuffix, NameValueCollection requestParams = null)
{
string url = GetUrl(methodSuffix)
if (requestParams != null && requestParams.Count > 0)
serviceAdress = AddParamsToUrl(url, requestParams);
var webRequest = WebRequest.CreateHttp(licServiceAdress);
webRequest.Method = "POST";
//The Timeout property indicates the length of time, in milliseconds,
//until the request times out and throws a WebException.
//The Timeout property affects only synchronous requests made with the GetResponse method.
//https://docs.microsoft.com/en-us/dotnet/api/system.net.webrequest.timeout?view=netframework-4.8#remarks
webRequest.Timeout = (int)TimeSpan.FromSeconds(Configuration.ServerTimeout).TotalMilliseconds;
webRequest.Proxy = null;
webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
webRequest.Headers.Add("Accept-Encoding", "gzip");
return webRequest;
}
private async Task<string> Send()
{
try
{
_httpRequest = await Task.Run(() => CreateRequest(_methodSuffix, _requestParams)).ConfigureAwait(false);
UTF8Encoding encoding = new UTF8Encoding();
byte[] requestBodyBytes = null;
if (_requestBody == null)
requestBodyBytes = encoding.GetBytes("");
else
requestBodyBytes = encoding.GetBytes(_requestBody);
_httpRequest.ContentType = "application/raw";
_httpRequest.ContentLength = requestBodyBytes.Length;
using (Stream newStream = await _httpRequest.GetRequestStreamAsync().ConfigureAwait(false))
{
await newStream.WriteAsync(requestBodyBytes, 0, requestBodyBytes.Length).ConfigureAwait(false);
}
using (var webResponse = (HttpWebResponse)await _httpRequest.GetResponseAsync().ConfigureAwait(false))
{
using (var responseStream = webResponse.GetResponseStream())
if (responseStream != null)
using (var reader = new StreamReader(responseStream))
return await reader.ReadToEndAsync().ConfigureAwait(false);
return "";
}
}
catch (Exception ex)
{
Log($"Request failed. Uri: '{_httpRequest.RequestUri.AbsoluteUri}'. {ex}");
throw;
}
}
我需要知道为什么套接字数据没有显示在Wireshark中。如何诊断呢?