Ошибка 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();
}

Большое спасибо :)


person StackTrace    schedule 27.04.2012    source источник
comment
Какое антивирусное приложение установлено на ноутбуках?   -  person Martin James    schedule 27.04.2012
comment
Просто стандартные средства безопасности Windows, хотя на одном из ноутбуков есть Spybot. Я не думаю, что это проблема, потому что на настольных компьютерах работает Kaspersky или Norton, и у меня нет проблем с этими машинами.   -  person StackTrace    schedule 27.04.2012
comment
Не могли бы вы показать код клиента? Как определяется, к какому IP / порту подключаться?   -  person Remy Lebeau    schedule 28.04.2012


Ответы (2)


IP-порт - это 16-битное целое число, поэтому максимально допустимый номер порта - 0xFFFF (65535). Здесь происходит целочисленное переполнение. Поскольку желаемый номер порта (76567) не умещается в 16 битах, номер усекается и используются только младшие 16 бит. Это дает вам номер порта 11031. Строка addr.sin_port = htons(76567); должна дать вам предупреждение компилятора, поскольку аргумент htons() не может попасть в uint16_t.

person Andrey    schedule 13.07.2012

getaddrinfo() возвращает связанный список всех доступных адресов для заданных hints критериев. Даже если на машине есть только один сетевой адаптер, ей может быть назначено несколько IP-адресов, даже для localhost. Вы привязываете сокет сервера к первой найденной паре IP / Port, getaddrinfo(), поэтому возможно, что клиент пытается подключиться к другому IP / порту, который действительно не прослушивает сервер, например, если сервер привязан к вашему IP-адресу LAN / Internet, но вместо этого клиент подключается к 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();
}
person Remy Lebeau    schedule 28.04.2012
comment
Хорошая идея, я пробовал, но у меня та же проблема. Прекрасно работает на настольном компьютере, но не на ноутбуках с win7. Спасибо за предложение Реми :) - person StackTrace; 01.05.2012
comment
Затем используйте инструмент командной строки netstat или инструмент TCPView от SysInternal, чтобы убедиться, что сервер действительно прослушивает IP / порт, к которому пытается подключиться клиент, а затем убедитесь, что клиент действительно пытается подключиться к IP. / Порт, к которому, по вашему мнению, следует подключаться. - person Remy Lebeau; 02.05.2012
comment
Беглый взгляд на TCPView показывает следующее: Протокол: Локальный адрес TCP: ‹Имя моей машины› Локальный порт: 11031 Удаленный адрес: ‹Имя моей машины› Удаленный порт: 0 Статус: ПРОСЛУШИВАНИЕ Меня смущает то, что Я установил порт на 76567. Но ни локальный, ни удаленный порт не настроены на это. Еще раз спасибо, Реми. - person StackTrace; 08.05.2012
comment
11031 - это 0x2B17, а 76567 - это 0x12B17. Заметили сходство? Убедитесь, что вы правильно назначаете порт. - person Remy Lebeau; 08.05.2012
comment
Я думаю, что назначаю порт правильно addr.sin_port = htons(76567); Однако я использую MingGW, может это быть какая-то проблема кросс-компиляции или даже несовместимость в функции htons MinGW? Это довольно неприятная установка. Я использую Qt + MinGW для сервера и Visual Studio для клиентов (не мой выбор, мне приходится работать с устаревшим кодом :() - person StackTrace; 09.05.2012
comment
Боже, какой идиот! 76567 ›65536 !! Отсюда усечение в шестнадцатеричном формате 0x12B17 до 0x2B17. Изменен на порт с номером 10000, но по-прежнему возникает та же ошибка! Он отлично работает на настольных компьютерах под управлением XP и Win7 и работает на ноутбуках под управлением XP, но я получаю ошибку 10061 на ноутбуках с win7?!? Я могу подтвердить, что сервер подключается и прослушивает порт 10000, а брандмауэр Windows отключен. Я так запутался в этой ошибке! - person StackTrace; 09.05.2012
comment
Если вы запустите netstat -a, увидите ли вы локальный адрес 0.0.0.0:10000 в списке и в состоянии LISTENING? - person Remy Lebeau; 09.05.2012
comment
Если это так, и вы по-прежнему не можете подключиться к нему, значит, соединение блокируется чем-то другим, кроме брандмауэра Windows, например антивирусным / антивирусным приложением, плохим сетевым драйвером или чем-то еще. - person Remy Lebeau; 09.05.2012
comment
netstat -a показывает Local Address 0.0.0.0:10000 и State LISTENING. Разве там не должно быть 127.0.0.1:10000? Я собираюсь найти и выключить любое программное обеспечение безопасности, чтобы посмотреть, смогу ли я найти, что блокирует этот порт. Спасибо за помощь, Реми, очень признателен :) - person StackTrace; 10.05.2012
comment
Нет, он должен сказать 0.0.0.0, а не 127.0.0.1, потому что вы на самом деле привязаны к 0.0.0.0. Это подстановочный адрес INADDR_ANY, который позволяет подключаться к любому IP-адресу на машине, включая 127.0.0.1. - person Remy Lebeau; 10.05.2012