场景:
在winform窗体里进行post请求,服务端是python-django写的。
现象:
可以进行网络请求并返回数据,但是在winform窗体关闭时服务端出现了异常:
Exception happened during processing of request from ('127.0.0.1', 63951)
Traceback (most recent call last):
File "C:\Python\Python37\lib\socketserver.py", line 650, in process_request_thread
self.finish_request(request, client_address)
File "C:\Python\Python37\lib\socketserver.py", line 360, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "C:\Python\Python37\lib\socketserver.py", line 720, in __init__
self.handle()
File "C:\Python\Python37\lib\site-packages\django\core\servers\basehttp.py", line 171, in handle
self.handle_one_request()
File "C:\Python\Python37\lib\site-packages\django\core\servers\basehttp.py", line 179, in handle_one_request
self.raw_requestline = self.rfile.readline(65537)
File "C:\Python\Python37\lib\socket.py", line 589, in readinto
return self._sock.recv_into(b)
ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
C#网络请求的代码如下:
string Url = "http://localhost:8000/calc";
string jsonParam = "{\"color1\":\"#ccff66\",\"color2\":\"#ccff77\"}";
var request = (HttpWebRequest)WebRequest.Create(Url);
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8";
var byteData = Encoding.UTF8.GetBytes(jsonParam);
var length = byteData.Length;
request.ContentLength = length;
var writer = request.GetRequestStream();
writer.Write(byteData, 0, length);
writer.Close();
var response = (HttpWebResponse)request.GetResponse();
var responseStream = response.GetResponseStream();
var streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
var responseString = streamReader.ReadToEnd();
streamReader.Close();
responseStream.Close();
原因:
从异常日志可以看出,异常是在读取数据的时候抛出的。
导致“Connection reset”的原因是服务器端因为某种原因关闭了Connection,而客户端依然在读写数据,此时服务器会返回复位标志“RST”,“RST”标志表示我不再发送数据也不接收数据了,然后此时客户端就会提示“java.net.SocketException: Connection reset”。
另一个比较常见的异常是“Connection reset by peer”,它和“Connection reset”的区别在于:
- 服务器返回了“RST”时,如果此时客户端正在从Socket套接字的输出流中读数据则会提示Connection reset”;
- 服务器返回了“RST”时,如果此时客户端正在往Socket套接字的输入流中写数据则会提示“Connection reset by peer”。
分析:
C#中用HttpWebRequest进行网络请求时默认是长连接,可以打印request.KeepAlive值确认。因此建立连接后,在关闭窗口时会向服务端进行挥手来关闭TCP连接。
而django中进行网络请求默认是短连接,这就导致客户端向服务端挥手时,服务端已经关闭了连接,出现异常。这里不敢确认,后面有时间研究一下吧
解决:
知道了原因就可以从以下方面来解决:
- 异常后重试
- 客户端和服务端统一使用TCP长链接
- 客户端和服务端统一使用TCP短链接
最终解决方法是在客户端请求时设置为短连接:
request.KeepAlive = false;
参考:https://blog.csdn.net/maligebazi/article/details/80304894