Winsock极简HTTP服务器半数请求报ERR_CONNECTION_ABORTED原因
问题描述
我尝试在Windows平台编写一个极简HTTP服务器,通过Chrome访问http://127.0.0.1:5000查看响应。下述代码有时可正常返回"Hello World",但半数场景下请求会失败,Chrome抛出ERR_CONNECTION_ABORTED错误,即便重启服务器问题仍复现,需要定位故障原因。
错误截图:
问题代码:
#include <winsock2.h> #include <iostream> #pragma comment(lib, "ws2_32.lib") int main() { WSADATA WSAData; SOCKET sock, csock; SOCKADDR_IN sin, csin; WSAStartup(MAKEWORD(2,0), &WSAData); sock = socket(AF_INET, SOCK_STREAM, 0); sin.sin_addr.s_addr = INADDR_ANY; sin.sin_family = AF_INET; sin.sin_port = htons(5000); bind(sock, (SOCKADDR *) &sin, sizeof(sin)); listen(sock, 0); while(1) { int sinsize = sizeof(csin); if((csock = accept(sock, (SOCKADDR *) &csin, &sinsize)) != INVALID_SOCKET) { std::string response = "HTTP/1.1 200 OK\nConnection: close\nContent-Length: 11\n\nHello World"; send(csock, response.c_str(), response.size(), 0); std::cout << "done"; closesocket(csock); } } return 0; }
故障原因
核心问题是连接关闭逻辑不符合TCP和HTTP规范,具体触发点如下:
- 代码接受连接后完全不读取客户端发送的HTTP请求,直接发送响应就调用
closesocket。此时socket接收缓冲区里还存着浏览器发来的未读请求数据,Windows内核会直接丢弃这些未读数据,向客户端发送RST重置包而非走正常的TCP四次挥手流程。Chrome收到RST包就会直接中断连接,抛出ERR_CONNECTION_ABORTED错误。偶发成功纯粹是时序巧合:如果浏览器刚好在接收到RST前读完了完整响应,就会显示内容,否则直接报错。 - HTTP响应头使用
\n作为换行符,不符合HTTP协议要求的\r\n(CRLF)换行规范,浏览器严格解析模式下会判定响应非法。 listen函数的backlog参数设为0,Windows下该配置会让待处理连接队列长度极小,Chrome访问页面时通常会并行发起页面请求、favicon请求等多个连接,队列满后新连接会被直接拒绝,进一步提升故障概率。
修复方案
按以下点调整代码即可解决问题:
- 发送响应前,先循环调用
recv读取客户端请求,直到读到\r\n\r\n标记(HTTP请求头结束标识),确认请求接收完成。 - 将响应头里的所有换行符从
\n替换为\r\n,符合HTTP协议规范。 - 发送完响应后,先调用
shutdown(csock, SD_SEND)触发TCP优雅关闭,等待客户端确认收到所有数据后,再调用closesocket关闭连接,避免内核发送RST包。 - 将
listen的第二个参数(连接队列长度)调整为合理值,比如10。
内容的提问来源于stack exchange,提问作者Basj
相关产品推荐
相关产品推荐

