Я новичок в сетевом программировании, так что это меня несколько дней озадачивало.
Я написал 2 приложения: одно - сервер, другое - клиент.
Я хочу, чтобы они сделали следующее: когда я предоставляю клиенту IP-адрес, клиент подключается к серверу на машине с предоставленным IP-адресом.
Я проверил это, открыв сервер и клиент на моем ПК, введя адрес обратной связи (127.0.0.1). Клиент подключился к серверу нормально (и я мог даже отправлять текстовые сообщения друг от друга).
Так что я попробовал дальше. Я погуглил свой IP (который был 113.20.98.124) и затем передал его моему клиенту. Я ожидал, что клиент также подключится к серверу, но этого не произошло. Клиент завершил работу и сказал, что время соединения истекло (WSAETIMEDOUT 10060).
Что я хочу спросить: почему я не могу использовать свой IP, чтобы сообщить клиенту, что он должен подключиться к моему серверу? Это даже вещь?
Вот мои коды сервера и клиента (на случай, если я что-то сделал не так):
(я кодировал, используя VS2017 в Windows)
Клиент:
#include <iostream>
#include <WS2tcpip.h>
#include <winsock2.h>
#include <string>
//The port which will be used to connect to server
#define PORT "7777"
std::string getIPAddress()
{
std::string out;
std::cout << "IP/Domain to connect to: ";
std::cin >> out;
std::cin.ignore();
return out;
}
//Print out error code and exit the program in case something goes wrong
void failure_exit(std::string message, int exitVal)
{
std::cerr << message
<< " Error code: " << WSAGetLastError() << " \n";
WSACleanup();
std::cin.get();
exit(exitVal);
}
int main(int argc, char *argv[])
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1, 0), &wsaData) != 0)
failure_exit("WSAStartup failed!", 1);
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; //AF_INET or AF_INET6 are totally fine
hints.ai_socktype = SOCK_STREAM; //TCP connection
//Get the IP from user
std::string IPconnect = getIPAddress();
//A pointer to a linked list of juicy results we can use
addrinfo *result(nullptr);
//Prepare the addrinfo for a connecting socket
if (getaddrinfo(IPconnect.c_str(), PORT, &hints, &result) != 0)
failure_exit("getaddrinfo failed!", 2);
/*PREPARING A SOCKET*/
SOCKET sockfd;
//A pointer to one of the addrinfos from result, which is a usable one
//'chosen' will also be used in connect() call
addrinfo *chosen(result);
//Run through the results got from getaddrinfo and pick the first usable addrinfo
for (; chosen != nullptr; chosen = chosen->ai_next)
{
//see if sockfd is legit to use
if ((sockfd = socket(chosen->ai_family, chosen->ai_socktype, chosen->ai_protocol)) != -1)
break;
}
freeaddrinfo(result);
//Socket preparation failed
if (sockfd<=0)
failure_exit("Socket preparation failed!", 3);
/*CONNECT!*/
std::cout << "Connecting... 20 seconds until timed out.\n";
if (connect(sockfd, chosen->ai_addr, chosen->ai_addrlen) != 0)
failure_exit("Failed to connect!", 4);
std::cout << "Connected!\n";
WSACleanup();
std::cin.get();
return 0;
}
Сервер:
#include <iostream>
#include <WS2tcpip.h>
#include <winsock2.h>
#include <string>
//The port which this server will be using
//to listen to incoming connections
#define PORT "7777"
//Limits how many pending connections
//can be queued up
#define BACKLOG 10
void failure_exit(std::string message, int exitVal)
{
std::cerr << message
<< " Error code: " << WSAGetLastError() << " \n";
WSACleanup();
std::cin.get();
exit(exitVal);
}
int main(int argc, char* argv[])
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(1, 0), &wsa) != 0)
failure_exit("WSAStartup failed!", 1);
addrinfo hints;
memset(&hints, 0, sizeof(hints));
//IPv4 or IPv6 are both Ok
hints.ai_family = AF_INET;
//This addrinfo will be used for binding
hints.ai_flags = AI_PASSIVE;
//TCP connection
hints.ai_socktype = SOCK_STREAM;
addrinfo *result;
if (getaddrinfo(NULL, PORT, &hints, &result) != 0)
failure_exit("getaddrinfo failed!", 3);
//PREPARE A SOCKET
SOCKET sockfd(0);
//The usable addrinfo will be pointed to by 'chosen'
addrinfo *chosen(result);
//Loop through the results to find a suitable one
for (; chosen != nullptr; chosen = chosen->ai_next)
{
sockfd = socket(chosen->ai_family, chosen->ai_socktype, chosen->ai_protocol);
//Stop at the first usable
if (sockfd != -1)
break;
}
freeaddrinfo(result);
//Check for preparation failure
if (sockfd <= 0)
failure_exit("Socket preparation failed!", 4);
//Bind the socket above to my chosen PORT
if (bind(sockfd, chosen->ai_addr, chosen->ai_addrlen) == -1)
failure_exit("Binding failed!", 5);
//Start listening for incoming connections
if (listen(sockfd, BACKLOG) == -1)
failure_exit("Listening failed!", 6);
//The new socket to be returned by accept()
SOCKET newfd;
sockaddr_storage newConnection;
socklen_t newlength(sizeof(newConnection));
std::cout << "Anyone?\n";
//Accept a pending connection
if ((newfd = accept(sockfd, reinterpret_cast<sockaddr*>(&newConnection), &newlength)) == -1)
failure_exit("Accepting connection failed!", 7);
std::cout << "Connection accepted!\n";
WSACleanup();
std::cin.get();
return 0;
}
Все, что я узнал о сетевом программировании, получено из http://beej.us/guide/.