Ошибка WinSock 10061
Я написал простое клиент-серверное приложение, использующее winsock. Сервер и клиент соединяются и обмениваются данными через TCP-порт 76567 (просто случайное число, которое я выбрал) на локальном хосте. Я проверил его на трех рабочих столах, на двух из которых установлена XP, а на другом - Win7, я также проверил его на четырех ноутбуках, на трех с Win7 и на одном с XP. Приложение прекрасно работает на всех настольных компьютерах и на ноутбуке с XP, но на всех трех ноутбуках с Win7 я получаю ошибку 10061, когда клиент пытается подключиться к серверу!
Я отключил брандмауэр, но проблема не исчезла, я также посмотрел вокруг, чтобы выяснить причину этой ошибки, и похоже, что клиент пытается подключиться к серверу, который не слушает. Однако серверный вызов listen() успешно возвращается! Очень странно, что проблема возникает только на ноутбуках с Win7, есть идеи?
Вот мой код инициализации сокета:
// Initialise Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(iResult != 0)
{
printf("WSAStartup failed: %d\n", iResult);
}
// Create a server socket
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if(iResult != 0)
{
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
}
// Create a socket to listen for clients
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if(listenSocket == INVALID_SOCKET)
{
printf("Error at socket(): %d\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
}
// Bind socket to ip address and port
iResult = bind(listenSocket, result->ai_addr, (int) result->ai_addrlen);
if(iResult == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(listenSocket);
WSACleanup();
}
freeaddrinfo(result);
// Listen for connection requests
if(listen(listenSocket, SOMAXCONN) != 0)
{
printf("Listen failed with error: %d\n", WSAGetLastError());
closesocket(listenSocket);
WSACleanup();
}
Большое спасибо:)
2 ответа
IP-порт является 16-разрядным целым числом, поэтому максимально допустимый номер порта равен 0xFFFF (65535). То, что происходит здесь, является своего рода целочисленным переполнением. Поскольку требуемый номер порта (76567) не умещается в 16 бит, номер усекается, и используются только младшие 16 бит. Это дает вам номер порта 11031. Линия addr.sin_port = htons(76567);
должен дать вам предупреждение компилятора, так как аргумент htons()
не может найти uint16_t
,
getaddrinfo()
возвращает связанный список всех доступных адресов для данного hints
критерии. Даже если у машины есть только один сетевой адаптер, ему может быть назначено несколько IP-адресов, даже для localhost. Вы привязываете сокет сервера к первой паре IP / порт, которая getaddrinfo()
найдено, поэтому возможно, что клиент может пытаться подключиться к другому IP / порту, который на самом деле не прослушивает сервер, например, если сервер привязан к вашей локальной сети / интернет-IP, но клиент подключается к 127.0.0.1
вместо. Клиент не может подключиться к 127.0.0.1
если сервер не связан с 127.0.0.1
,
В среде с несколькими компьютерами и несколькими IP-адресами следует использовать подстановочный знак 0.0.0.0
IP (иначе INADDR_ANY
) при звонке bind()
, вместо result->ai_addr
, Это свяжет сокет со всеми доступными IP-адресами всех установленных сетевых адаптеров. Таким образом, клиент может подключиться к любому IP-адресу, к которому привязан сервер, включая 127.0.0.1
, На самом деле, учитывая код, который вы показали, вам даже не нужно использовать getaddrinfo()
совсем:
// Initialise Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(iResult != 0)
{
printf("WSAStartup failed: %d\n", iResult);
}
// Create an IPv4 server socket to listen for IPv4 clients
listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenSocket == INVALID_SOCKET)
{
printf("Error at socket(): %d\n", WSAGetLastError());
WSACleanup();
}
// Bind socket to IPv4 address and port
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(76567);
addr.sin_addr.s_addr = INADDR_ANY;
iResult = bind(listenSocket, (sockaddr*)&addr, sizeof(addr));
if(iResult == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
closesocket(listenSocket);
WSACleanup();
}
// Listen for IPv4 connection requests
if(listen(listenSocket, SOMAXCONN) != 0)
{
printf("Listen failed with error: %d\n", WSAGetLastError());
closesocket(listenSocket);
WSACleanup();
}