У меня проблема с подключением к серверу. При попытке привязать сервер к IP-адресу моего внешнего устройства я получил ошибку winsock: 10049 Невозможно назначить запрошенный адрес. Использование локального сервера работает правильно.
Этот IP-адрес: 192.168.0.202 пинг успешно.
Я работал на win8.1. Я отключил брандмауэр и Windows Defender, и это не помогло.
Код с серверной реализацией взят из http://www.planetchili.net/forum/viewtopic.php?f=3&т = 3433
#include "Server.h"
Server::Server(int PORT, bool BroadcastPublically) //Port = port to broadcast on. BroadcastPublically = false if server is not open to the public (people outside of your router), true = server is open to everyone (assumes that the port is properly forwarded on router settings)
{
//Winsock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
MessageBoxA(NULL, "WinSock startup failed", "Error", MB_OK | MB_ICONERROR);
exit(1);
}addr.sin_addr.s_addr = inet_addr("192.168.0.202");
addr.sin_port = htons(1234); //Port
addr.sin_family = AF_INET; //IPv4 Socket
sListen = socket(AF_INET, SOCK_STREAM, NULL); //Create socket to listen for new connections
if (bind(sListen, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) //Bind the address to the socket, if we fail to bind the address..
{
std::string ErrorMsg = "Failed to bind the address to our listening socket. Winsock Error:" + std::to_string(WSAGetLastError());
MessageBoxA(NULL, ErrorMsg.c_str(), "Error", MB_OK | MB_ICONERROR);
exit(1);
}
if (listen(sListen, SOMAXCONN) == SOCKET_ERROR) //Places sListen socket in a state in which it is listening for an incoming connection. Note:SOMAXCONN = Socket Oustanding Max Connections, if we fail to listen on listening socket...
{
std::string ErrorMsg = "Failed to listen on listening socket. Winsock Error:" + std::to_string(WSAGetLastError());
MessageBoxA(NULL, ErrorMsg.c_str(), "Error", MB_OK | MB_ICONERROR);
exit(1);
}
serverptr = this;
}
bool Server::ListenForNewConnection()
{
SOCKET newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen); //Accept a new connection
if (newConnection == 0) //If accepting the client connection failed
{
std::cout << "Failed to accept the client's connection." << std::endl;
return false;
}
else //If client connection properly accepted
{
std::cout << "Client Connected! ID:" << TotalConnections << std::endl;
Connections[TotalConnections] = newConnection; //Set socket in array to be the newest connection before creating the thread to handle this client's socket.
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(TotalConnections), NULL, NULL); //Create Thread to handle this client. The index in the socket array for this thread is the value (i).
//std::string MOTD = "MOTD: Welcome! This is the message of the day!.";
//SendString(TotalConnections, MOTD);
TotalConnections += 1; //Incremenent total # of clients that have connected
return true;
}
}
bool Server::ProcessPacket(int ID, Packet _packettype)
{
switch (_packettype)
{
case P_ChatMessage: //Packet Type: chat message
{
std::string Message; //string to store our message we received
if (!GetString(ID, Message)) //Get the chat message and store it in variable: Message
return false; //If we do not properly get the chat message, return false
//Next we need to send the message out to each user
for (int i = 0; i < TotalConnections; i++)
{
if (i == ID) //If connection is the user who sent the message...
continue;//Skip to the next user since there is no purpose in sending the message back to the user who sent it.
if (!SendString(i, Message)) //Send message to connection at index i, if message fails to be sent...
{
std::cout << "Failed to send message from client ID: " << ID << " to client ID: " << i << std::endl;
}
}
//std::cout << "Processed chat message packet from user ID: " << ID << std::endl;
if(Message == "go")
std::cout << "MESSAGE:GO!" << std::endl;
else if(Message == "left")
std::cout << "MESSAGE: GO LEFT!" << std::endl;
else if (Message == "right")
std::cout << "MESSAGE:GO RIGHT!" << std::endl;
else
std::cout << "MESSAGE:DO NOTHING!" << std::endl;
break;
}
default: //If packet type is not accounted for
{
std::cout << "Unrecognized packet: " << _packettype << std::endl; //Display that packet was not found
break;
}
}
return true;
}
void Server::ClientHandlerThread(int ID) //ID = the index in the SOCKET Connections array
{
Packet PacketType;
while (true)
{
if (!serverptr->GetPacketType(ID, PacketType)) //Get packet type
break; //If there is an issue getting the packet type, exit this loop
if (!serverptr->ProcessPacket(ID, PacketType)) //Process packet (packet type)
break; //If there is an issue processing the packet, exit this loop
}
std::cout << "Lost connection to client ID: " << ID << std::endl;
closesocket(serverptr->Connections[ID]);
return;
}
Есть идеи?
bind()
Функция используется для указания того, какой адрес серверной системы используется для приема соединений от удаленных клиентов, а не для указания, какому удаленному клиенту разрешено подключаться к серверу. bind()
Функция может использоваться только с адресами, которые действительны для самого сервера, но не для адресов удаленных устройств или хостов.
Чтобы определить, какому удаленному хосту разрешено подключаться к вашему серверу, вам необходимо принять подключение и подтвердить удаленный адрес в это время. Если адрес не правильный, соединение закрывается.
В общем, вы хотите использовать INADDR_ANY
если ваш сервер не является многодомным (более одного физического подключения к нескольким сетям), и только тогда, если вы пытаетесь ограничить подключения к одной из сетей, к которым подключен ваш сервер.
Winsock возвращает флаг ошибки 10049 (WSAEADDRNOTAVAIL) через свой API WSAGetLastError
всякий раз, когда приложение пытается связаться с неверным IP-адресом.
привязка к определенному IP-адресу означает, что всякий раз, когда вы запускаете программу (сервер), адрес должен быть действительным (доступным), но, тем не менее, DHCP выдает вам динамические IP-адреса каждый раз, когда вы отключаете / подключаете адаптер, так что вы адрес, который вы связывали с сервером в прошлый раз недопустимо исправить его, откройте cmd и введите:
ipconfig
вы получите список адресов ip4 / ip6, затем вы можете выбрать один из них и привязать свой сервер, однако этот метод действительно скучный, поэтому альтернативой является привязка к INADDR_ANY
так что вы позволяете системе делать работу за вас.
вам нужно только с клиента ввести адрес сервера и порт и подключиться.