Не удается привязать сокет winsock

#c #networking #winsock #winsock2

Вопрос:

Я довольно новичок в сети на c , поэтому я смотрел несколько учебных пособий, но, похоже, не могу понять, почему я не могу связать свой сокет. Может ли кто-нибудь объяснить мне, что я делаю не так? Вот мой код для привязки сокета.

 #include <stdlib.h>
#include <winsock2.h>

#pragma comment (lib,"ws2_32.lib")
#pragma warning( disable : 4996)
#define PORT 17027
int main()
{
    //creating socket
    SOCKET listenSocket = INVALID_SOCKET;
    listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    //bind socket
    struct sockaddr_in address;
    memset(amp;address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_port = htons(PORT);

    int bindValue = bind(listenSocket, (struct sockaddr *)amp;address, sizeof(address));
    if (bindValue == SOCKET_ERROR) {
        std::cout << WSAGetLastError() << std::endl; 
        return 1;
    }
 

Вывод: Не удалось привязать: 10038

Ответ №1:

Ошибка 10038 WSAENOTSOCK («Операция сокета на неустановленном компьютере»), что означает, что вы вызываете bind() недопустимого SOCKET . И действительно, вы не проверяете socket() , успешно ли это. Чего нет, поскольку вы не вызываете WSAStartup() первым, поэтому socket() происходит сбой с WSANOTINITIALISED ошибкой («Успешный WSAStartup еще не выполнен»).

Функция WSAStartup должна быть первой функцией сокетов Windows, вызываемой приложением или библиотекой DLL. Это позволяет приложению или библиотеке DLL указать требуемую версию сокетов Windows и получить подробную информацию о конкретной реализации сокетов Windows. Приложение или библиотека DLL могут выдавать дополнительные функции сокетов Windows только после успешного вызова WSAStartup.

Комментарии:

1. Одна из вещей, которую вы должны убрать из этого ответа, — это всегда проверять код возврата и убедиться, что вы понимаете, что подразумевает возвращаемое значение. В сетевом программировании вы должны быть религиозны с кодами возврата, потому что они редко просто работают/не работают. recv например , сообщает вам, сколько данных было прочитано (что не всегда соответствует запрошенному объему данных), или что сокет вежливо отключился, или что произошла ошибка, и вам придется позвонить еще WSAGetLAstError раз, чтобы узнать, в чем заключалась эта ошибка.

Ответ №2:

Вы должны указать, к какому интерфейсу вы хотите привязать сокет. Это делается путем установки sin_addr элемента sockaddr_in структуры.

Например, чтобы привязаться к интерфейсу с подстановочными INADDR_ANY знаками (чтобы иметь возможность получать соединения от всех интерфейсов), вы должны сделать что-то вроде этого:

 address.sin_addr.s_addr = htonl(INADDR_ANY);
 

В то время как для привязки к определенному интерфейсу вы должны сделать что-то вроде этого:

 address.sin_addr.s_addr = inet_addr("interface IP here");
 

Что касается отчетов об ошибках, API Winsock не настроен errno на ошибку (и errno используется perror() ). Вместо этого вам нужно использовать WSAGetLastError() , чтобы получить код ошибки и FormatMessage() получить описание ошибки.

Комментарии:

1. Я просто попытался добавить часть «address.sin_addr.s_addr = htonl(INADDR_ANY);» и изменил часть perror на WSAGetLastError, но она все еще не работает, и я не получаю ошибок.

2. @ReaperB_G Вы печатаете результат WSAGetLAstError() ? Нравится if (bindValue == SOCKET_ERROR) { std::cout << WSAGetLastError() << 'n'; return 1; }

3. Да, я неправильно сопоставлял функцию ошибок. Но теперь я получаю ошибку 10038.

4. @ReaperB_G Если вы будете следовать документации, на которую я ссылался, и перейдете по ней к кодам ошибок , вы увидите, что 10038 это означает WSAENOTSOCK , что «Работа сокета на не-сокете». socket Удалось ли позвонить? Вы это проверяли? Держу пари, что это не удалось, потому что вы забыли вызвать WSAStartup функцию. Не забывайте всегда проверять наличие ошибок для всех функций.

5. Хорошо, я добавил функцию WSAStartup и вызвал настройку сокета после этого, и это исправило это, спасибо за вашу помощь.