我在外部服务器(IIS)上部署了客户端桌面应用程序和Web服务。它们之间的通信基于HTTPWebrequest和HTTPWebresponse。该代码在IIS 8.0上运行正常,将其升级到IIS 8.5后,将响应发送给客户端停止工作。以下例外被抛在客户端:
system.io.ioexception:无法从传输中读取数据 连接:
现有的连接被强制关闭 远程主机。--->
system.net.sockets.socketException:
现有连接被远程主机强行关闭
at system.net.sockets.socket.receive(byte []缓冲区,int32 offset,int32 尺寸,socketflags socketflags)
at system.net.sockets.networkStream.Read(byte [] buffer,int32 offset, int32 size)
----内部异常堆栈跟踪---
at System.net.connectStream.Read(byte [] buffer,int32 offset,int32 尺寸)
在System.IO.Stream.internalCopyto(流目的地, int32缓冲)
at test.testhttpservice.getResponseString(httpwebresponse响应)
在服务器端,没有例外。服务器上的Wireshark和客户端计算机上的提琴手也没有任何线索。IIS跟踪日志显示所有数据已成功发送到客户端
在此处输入图像描述
客户端代码:
public static string GetResponse(string serviceUrl, string resourceUrl, string method, string xmlRequestBody, string authorization, string connectionName)
{
string responseMessage = null;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
var request = HttpWebRequest.Create(string.Concat(serviceUrl, resourceUrl)) as HttpWebRequest;
if (request != null)
{
request.ContentType = "application/xml";
request.Method = method;
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.Timeout = int.MaxValue;
//request.ServicePoint.ConnectionLimit = 1;
request.Headers.Add("Authorization", authorization);
request.Headers.Add("ConnectionName", connectionName);
}
if (xmlRequestBody != null)
{
byte[] requestBodyBytes = TBCCompressionService.Zip(xmlRequestBody.ToString());
request.ContentLength = requestBodyBytes.Length;
if (request.ContentLength > 0)
{
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);
}
}
}
if (request != null)
{
System.Net.ServicePointManager.Expect100Continue = false;
try
{
var response = request.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
responseMessage = GetResponseString(response);
}
else
{
responseMessage = response.StatusDescription;
}
}
catch(WebException ex)
{
var httpResponse = ex.Response as HttpWebResponse;
if (httpResponse != null
&& httpResponse.StatusCode == HttpStatusCode.BadRequest)
{
responseMessage = GetResponseString(ex.Response as HttpWebResponse);
}
else
{
throw ex;
}
}
}
return responseMessage;
}
private static string GetResponseString(HttpWebResponse response)
{
string result = string.Empty;
if(response != null)
{
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (MemoryStream memoryStream = new MemoryStream())
{
//this is the line when above exception is thrown.
responseStream.CopyTo(memoryStream);
result = TBCCompressionService.UnZip(memoryStream.ToArray());
}
}
}
}
return result;
}
服务器端代码:
public static void Send(string responseContent, HttpStatusCode? httpStatus)
{
HttpResponse response = HttpContext.Current.Response;
int waitCounter = 1000;
if (response.IsClientConnected)
{
response.Clear();
response.BufferOutput = true;
response.Buffer = true;
if (httpStatus != null)
{
response.StatusCode = (int)httpStatus.Value;
}
if (responseContent == null
|| string.IsNullOrWhiteSpace(responseContent))
{
response.StatusCode = (int)HttpStatusCode.NoContent;
}
else
{
byte[] responseContentZip = Zip(responseContent);
int responseContentLength = responseContentZip.Length;
response.ContentType = "text/xml";
response.AppendHeader("Content-Length", responseContentLength.ToString());
response.BinaryWrite(responseContentZip);
}
response.Flush();
//If this sleep is not present exception is thrown on the client side
//Unable to read data from the transport connection : An existing connection was forcibly closed by the remote host.
System.Threading.Thread.Sleep(waitCounter);
response.Close();
response.End();
}
else
{
logger.Error("Client was no longer connected to remote server. Response wasn't sent.");
}
}
非常奇怪的是,睡觉的AppPool线程会有所帮助,并让响应成功地到达客户端。在我看来,冲洗操作在连接之前没有结束,我在 system.web.dll 代码中寻找一些线索执行打破连接。
你可以使用限制服务点的数量
** webrequest.servicepoint.connectionlimit = 1;
**