前言
大家在写socket网络通信的时候,最容易碰到的问题就是10053与10054。那么这两个错误是怎么产生的呢?
10053 10054代表什么意思
微软的官方解释如下
10053
WSAECONNABORTED
Software caused connection abort. An established connection was aborted by the software in your host machine, possibly due to a data transmission time-out or protocol error.
10054
WSAECONNRESET
Connection reset by peer. An existing connection was forcibly closed by the remote host. This normally results if the peer application on the remote host is suddenly stopped, the host is rebooted, or the remote host uses a hard close (see setsockopt (Windows Sockets) for more information on the SO_LINGER option on the remote socket.) This error may also result if a connection was broken due to keep-alive activity detecting a failure while one or more operations are in progress. Operations that were in progress fail with WSAENETRESET. Subsequent operations fail with WSAECONNRESET.
两个的意思差不多,实际测试发现触发的条件也相似,都是因为收发消息的时候,发现对方的socket已经失效,是无效的连接。
有哪些条件可以出发这个情况呢
- 调用closesocket
- 程序直接退出
总而言之,就是对方的socket资源被系统回收了。
测试
测试一
服务端代码,接收到客户端连接就直接closesocket,服务端程序不要退出
SOCKET sserver; WORD VersionRequested; WSADATA WsaData; VersionRequested = MAKEWORD(2, 2); WSAStartup(VersionRequested, &WsaData); sserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN AddrClient; AddrClient.sin_family = AF_INET; AddrClient.sin_addr.s_addr = INADDR_ANY; AddrClient.sin_port = htons(9999); bind(sserver, (sockaddr*)&AddrClient, sizeof(AddrClient)); listen(sserver, 10); SOCKET sclient = accept(sserver, NULL, NULL); closesocket(sclient);
客户端代码,正常发送接收
int err = 0; WORD VersionRequested; WSADATA WsaData; VersionRequested = MAKEWORD(2, 2); WSAStartup(VersionRequested, &WsaData); SOCKET sserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN AddrServer; AddrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); AddrServer.sin_port = htons(9999); AddrServer.sin_family = AF_INET; connect(sserver, (SOCKADDR *)&AddrServer, sizeof(SOCKADDR)); char temp[] = "hello server"; int rs = send(sserver, temp, sizeof(temp) + 1, 0); err = WSAGetLastError(); std::cout << err << std::endl; char buff[1024] = { 0 }; rs = recv(sserver, buff, sizeof(buff), 0); err = WSAGetLastError(); std::cout << err << std::endl; rs = send(sserver, temp, sizeof(temp) + 1, 0); err = WSAGetLastError(); std::cout << err << std::endl; rs = recv(sserver, buff, sizeof(buff), 0); err = WSAGetLastError(); std::cout << err << std::endl;
输出
0 10054 10054 10054
服务端在建立好连接后,直接关闭了socket,客户端这边在第一次发送的时候,应该是由于比较快,认为现在还是正常的,发送到了缓冲区,是正常的。在后面接收发送的时候,发现socket有问题了,报了10054的错误。
测试二
服务端程序,建立好连接后,并没有调用closesocket,而是直接程序退出了
SOCKET sserver; WORD VersionRequested; WSADATA WsaData; VersionRequested = MAKEWORD(2, 2); WSAStartup(VersionRequested, &WsaData); sserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN AddrClient; AddrClient.sin_family = AF_INET; AddrClient.sin_addr.s_addr = INADDR_ANY; AddrClient.sin_port = htons(9999); bind(sserver, (sockaddr*)&AddrClient, sizeof(AddrClient)); listen(sserver, 10); SOCKET sclient = accept(sserver, NULL, NULL);
return;
客户端程序,与上面一样,正常接收发送
int err = 0; WORD VersionRequested; WSADATA WsaData; VersionRequested = MAKEWORD(2, 2); WSAStartup(VersionRequested, &WsaData); SOCKET sserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN AddrServer; AddrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); AddrServer.sin_port = htons(9999); AddrServer.sin_family = AF_INET; connect(sserver, (SOCKADDR *)&AddrServer, sizeof(SOCKADDR)); char temp[] = "hello server"; int rs = 0; rs = send(sserver, temp, sizeof(temp) + 1, 0); err = WSAGetLastError(); std::cout << err << std::endl; char buff[1024] = { 0 }; rs = recv(sserver, buff, sizeof(buff), 0); err = WSAGetLastError(); std::cout << err << std::endl; rs = send(sserver, temp, sizeof(temp) + 1, 0); err = WSAGetLastError(); std::cout << err << std::endl; rs = recv(sserver, buff, sizeof(buff), 0); err = WSAGetLastError(); std::cout << err << std::endl;
输出
0 10054 10054 10054
可以看到,程序直接退出,与closesocket是一样的现象。
测试三
服务端socket连接成功后就close,但是程序不退出
SOCKET sserver; WORD VersionRequested; WSADATA WsaData; VersionRequested = MAKEWORD(2, 2); WSAStartup(VersionRequested, &WsaData); sserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN AddrClient; AddrClient.sin_family = AF_INET; AddrClient.sin_addr.s_addr = INADDR_ANY; AddrClient.sin_port = htons(9999); bind(sserver, (sockaddr*)&AddrClient, sizeof(AddrClient)); listen(sserver, 10); SOCKET sclient = accept(sserver, NULL, NULL); closesocket(sclient);
客户端正常接收,只不过在连接成功后,sleep一会
int err = 0; WORD VersionRequested; WSADATA WsaData; VersionRequested = MAKEWORD(2, 2); WSAStartup(VersionRequested, &WsaData); SOCKET sserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN AddrServer; AddrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); AddrServer.sin_port = htons(9999); AddrServer.sin_family = AF_INET; connect(sserver, (SOCKADDR *)&AddrServer, sizeof(SOCKADDR)); Sleep(1000); char temp[] = "hello server"; int rs = 0; rs = send(sserver, temp, sizeof(temp) + 1, 0); err = WSAGetLastError(); std::cout << err << std::endl; char buff[1024] = { 0 }; rs = recv(sserver, buff, sizeof(buff), 0); err = WSAGetLastError(); std::cout << err << std::endl; rs = send(sserver, temp, sizeof(temp) + 1, 0); err = WSAGetLastError(); std::cout << err << std::endl; rs = recv(sserver, buff, sizeof(buff), 0); err = WSAGetLastError(); std::cout << err << std::endl;
输出
0 10053 10053 10053
结果变成了10053,与测试一唯一的区别就是增加了sleep
测试四
服务端连接成功后,直接退出程序
SOCKET sserver; WORD VersionRequested; WSADATA WsaData; VersionRequested = MAKEWORD(2, 2); WSAStartup(VersionRequested, &WsaData); sserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN AddrClient; AddrClient.sin_family = AF_INET; AddrClient.sin_addr.s_addr = INADDR_ANY; AddrClient.sin_port = htons(9999); bind(sserver, (sockaddr*)&AddrClient, sizeof(AddrClient)); listen(sserver, 10); SOCKET sclient = accept(sserver, NULL, NULL); closesocket(sclient); return;
客户端还是建立连接后,sleep一会,然后再正常收发消息
int err = 0; WORD VersionRequested; WSADATA WsaData; VersionRequested = MAKEWORD(2, 2); WSAStartup(VersionRequested, &WsaData); SOCKET sserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN AddrServer; AddrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); AddrServer.sin_port = htons(9999); AddrServer.sin_family = AF_INET; connect(sserver, (SOCKADDR *)&AddrServer, sizeof(SOCKADDR)); Sleep(1000); char temp[] = "hello server"; int rs = 0; rs = send(sserver, temp, sizeof(temp) + 1, 0); err = WSAGetLastError(); std::cout << err << std::endl; char buff[1024] = { 0 }; rs = recv(sserver, buff, sizeof(buff), 0); err = WSAGetLastError(); std::cout << err << std::endl; rs = send(sserver, temp, sizeof(temp) + 1, 0); err = WSAGetLastError(); std::cout << err << std::endl; rs = recv(sserver, buff, sizeof(buff), 0); err = WSAGetLastError(); std::cout << err << std::endl;
输出
0 10053 10053 10053
总结
触发10053/10054的条件就是,a与b创建了socket连接,如果a通过socket向b收发消息的时候,b那边的连接已经不存在了,a就会收到10053或是10054。从测试来看,如果socket断开后立马操作,就会触发10054,如果做了一些其他的事情再操作,就会触发10053.
10053和10054的区别是,socket异常后,会有一个fin消息,如果在这个消息到达之前就reset,就会触发10054;如果这个消息已经到达,再reset,就会触发10053.