Вы используете gethostbyname()
(без проверки ошибок), чтобы получить публичный IP (Есть и другие способы, чтобы получить этот IP без использования DNS-поиска). Если ваш сервер находится за NAT/маршрутизатором (как подразумевается вашим комментарием, что вы должны перенаправить порт на свой сервер), тогда вы привязываетесь к неправильному IP-адресу. Вы можете привязываться только к IP-адресу, принадлежащему сетевому адаптеру, который является локальным для серверной машины. В среде NAT это означает привязку к IP-адресу частной сети, который был назначен серверу, а не публичному IP-адресу NAT. NAT будет перенаправлять соединения из своего общедоступного IP-адреса WAN на собственный IP-адрес сервера, а затем сервер может принимать соединения на своем личном IP-адресе LAN. Это также позволяет серверу принимать соединения от клиентов, работающих на других компьютерах с той же локальной сетью.
Кроме того, inet_addr()
ожидает IP-адрес в формате точечной строки, но gethostbyname()
вместо этого возвращает IP-адреса в двоичном формате. Когда поле hostent::h_addrtype
равно AF_INET
(которому не гарантируется возврат gethostbyname()
), поле hostent::h_addr_list
содержит указатели на in_addr
структуры, которые затем можно назначить как-есть для поля sin.sin_addr
.
Было бы проще просто привязать к INADDR_ANY
, чтобы сервер мог принимать соединения по любому локальному IP-адресу, а не привязываться к конкретному IP-адресу.
Попробуйте это:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShow)
{
WSADATA wsaData;
int retVal;
retVal = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (retVal != 0)
{
MessageBox(NULL, "Unable to initialize WinSock", "SOCKET ERROR", MB_OK);
return SOCKET_ERROR;
}
/// Creating socket
SOCKET servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (servSock == INVALID_SOCKET)
{
WSACleanup();
MessageBox(NULL, "Unable to create socket", "SOCKET ERROR", MB_OK);
return SOCKET_ERROR;
}
/// Filling in sockaddr_in struct
SOCKADDR_IN sin = {0};
sin.sin_family = AF_INET;
sin.sin_port = htons(8844);
//sin.sin_addr.s_addr = inet_addr("192.16.0.1"); // whatever your LAN IP is
sin.sin_addr.s_addr = INADDR_ANY;
retVal = bind(servSock, (LPSOCKADDR)&sin, sizeof(sin));
if (retVal == SOCKET_ERROR)
{
retVal = WSAGetLastError();
MessageBox(NULL, "Unable to bind socket", "SOCKET ERROR", MB_OK);
closesocket(servSock);
WSACleanup();
return SOCKET_ERROR;
}
retVal = listen(servSock, ...);
if (retVal == SOCKET_ERROR)
{
retVal = WSAGetLastError();
MessageBox(NULL, "Unable to listen on socket", "SOCKET ERROR", MB_OK);
closesocket(servSock);
WSACleanup();
return SOCKET_ERROR;
}
...
closesocket(servSock);
WSACleanup();
return 0;
}
В качестве альтернативы, вы можете использовать getaddrinfo()
вместо и пусть он расскажет вам, какие IP (ы) для привязки к:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShow)
{
WSADATA wsaData;
int retVal;
retVal = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (retVal != 0)
{
MessageBox(NULL, "Unable to initialize WinSock", "SOCKET ERROR", MB_OK);
return SOCKET_ERROR;
}
addrinfo hints = {0};
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
addrinfo *addrs
retVal = getaddrinfo(NULL, "8844", &hints, &addrs);
if (retVal != 0)
{
MessageBox(NULL, "Unable to get addr info", "SOCKET ERROR", MB_OK);
WSACleanup();
return SOCKET_ERROR;
}
std::vector<SOCKET> servSocks;
/// Creating sockets
for(addrinfo *addr = addrs; addr != NULL; addr = addr->ai_next)
{
SOCKET servSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (servSock == INVALID_SOCKET)
continue;
retVal = bind(servSock, addr->ai_addr, addr->ai_addrlen);
if (retVal == SOCKET_ERROR)
{
closesocket(servSock);
continue;
}
retVal = listen(servSock, ...);
if (retVal == SOCKET_ERROR)
{
closesocket(servSock);
continue;
}
servSocks.push_back(servSock);
}
freeaddrinfo(addrs);
if (servSocks.empty())
{
MessageBox(NULL, "Unable to prepare listening socket(s)", "SOCKET ERROR", MB_OK);
WSACleanup();
return SOCKET_ERROR;
}
...
std::for_each(servSocks.begin(), servSocks.end(), &::closesocket);
WSACleanup();
return 0;
}
В любом случае, ваш сервис NO-IP просто сопоставляет статическое имя хоста с текущим общедоступным IP-адресом NAT, не более того. Когда клиент хочет подключиться к имени хоста, он сначала разрешает имя хоста текущему IP-адресу, а затем подключается к этому IP-адресу. Он подключается к вашему NAT-маршрутизатору, а не к вашему серверу напрямую. Маршрутизатор перенаправляет клиент на частный IP-адрес локальной сети, к которому привязан ваш сервер, где сервер может принять соединение. Поэтому убедитесь, что правила перенаправления портов вашего маршрутизатора настроены правильно. Если это не работает правильно, вы должны задать вопрос по адресу ServerFault.com, поскольку это проблема с сетью, а не проблема с кодировкой.
И номер ошибки был? NB номер ошибки * до * вы вызываете 'WSACleanup()'. Публикация вопроса без сообщения об ошибке или номера здесь является пустой тратой времени. – EJP
захватите 'WSAGetLastError()' перед вызовом 'WSACleanup' и распечатайте его. Затем просмотрите здесь код ошибки (https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668 (v = vs.85) .aspx), чтобы узнать, что произошло. – user4581301
Затем найдите код ошибки в ** MSDN **, чтобы узнать, что произошло. @ user4581301 – EJP