#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 и вызвал настройку сокета после этого, и это исправило это, спасибо за вашу помощь.