C++ 服务器和客户端都在PC上运行。客户端可以使用PC的IP连接到服务器吗?
我是网络编程新手,所以这件事困扰了我好几天 我写了两个应用程序:一个是服务器,一个是客户端 我希望他们做的是:当我向客户机提供IP地址时,客户机将使用提供的IP连接到机器上的服务器 我在PC上打开服务器和客户机,输入环回地址(127.0.0.1),测试了它。客户端与服务器连接良好(我甚至可以互相发送文本消息) 所以我进一步尝试。我在谷歌上搜索了我的IP(113.20.98.124),然后把它提供给我的客户。我原以为客户端也会连接到服务器,但那没有发生。客户端终止并说连接超时(WSAETIMEDOUT 10060) 我想问的是:为什么我不能使用我的IP来告诉客户端连接到我的服务器?这是一件事吗 以下是我的服务器和客户端代码(以防我做错了什么): (我在Windows上使用VS2017编码) 客户:C++ 服务器和客户端都在PC上运行。客户端可以使用PC的IP连接到服务器吗?,c++,networking,C++,Networking,我是网络编程新手,所以这件事困扰了我好几天 我写了两个应用程序:一个是服务器,一个是客户端 我希望他们做的是:当我向客户机提供IP地址时,客户机将使用提供的IP连接到机器上的服务器 我在PC上打开服务器和客户机,输入环回地址(127.0.0.1),测试了它。客户端与服务器连接良好(我甚至可以互相发送文本消息) 所以我进一步尝试。我在谷歌上搜索了我的IP(113.20.98.124),然后把它提供给我的客户。我原以为客户端也会连接到服务器,但那没有发生。客户端终止并说连接超时(WSAETIMEDO
#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;
}
#包括
#包括
#包括
#包括
//将用于连接到服务器的端口
#定义端口“7777”
std::string getIPAddress()
{
std::字符串输出;
std::cout>out;
std::cin.ignore();
返回;
}
//打印出错误代码,并在出现问题时退出程序
无效失败\u退出(std::字符串消息,int exitVal)
{
标准::cerr ai_协议)!=-1)
打破
}
freeaddrinfo(结果);
//套接字准备失败
如果(sockfdai_addrlen)!=0)
失败退出(“连接失败!”,4);
标准::cout ai_addrlen)==-1)
失败退出(“绑定失败!”,5);
//开始侦听传入的连接
如果(侦听(sockfd,BACKLOG)=-1)
失败退出(“侦听失败!”,6);
//accept()返回的新套接字
插座newfd;
sockaddr_存储新连接;
socklen_t newlength(sizeof(newConnection));
当你用谷歌搜索你的IP时,你得到了外界所看到的公共IP。如果您的电脑直接连接到Internet调制解调器,则该IP属于您的电脑。但是,如果您的电脑位于网络路由器后面(这在现在有许多Internet连接设备的家庭中非常常见),则该IP属于您的网络路由器,而不是您的电脑
您的服务器应用程序只能在已直接分配给正在运行的PC的本地/局域网IP上侦听。如果这台电脑在网络路由器后面运行,它就不能监听路由器的公共IP
服务器代码绑定其侦听套接字的方式是,它侦听分配给正在运行的PC的所有可用IPv4 IP。要了解这些IP实际上是什么,可以使用Windows的命令行ipconfig
工具。或者,在服务器代码中,可以使用或API
如果您的客户端与服务器应用程序运行在同一台PC/网络上,它可以直接连接到服务器正在侦听的任何本地/LAN IP。但是,如果客户端运行在不同的网络上(即,在Internet上的另一台PC上),则它需要连接到您的公共IP。在公共IP属于网络路由器的情况下,路由器需要配置为将给定:
上的入站连接转发到服务器PC的
(即,从113.20.98.124:777
转发到类似192.168.0.1:777
,或实际分配给服务器PC的任何IP).当你在谷歌上搜索你的IP时,你得到了外界所看到的公共IP。如果您的电脑直接连接到Internet调制解调器,则该IP属于您的电脑。但是,如果您的电脑位于网络路由器后面(这在现在有许多Internet连接设备的家庭中非常常见),则该IP属于您的网络路由器,而不是您的电脑
您的服务器应用程序只能在已直接分配给正在运行的PC的本地/局域网IP上侦听。如果这台电脑在网络路由器后面运行,它就不能监听路由器的公共IP
服务器代码绑定其侦听套接字的方式是,它侦听分配给正在运行的PC的所有可用IPv4 IP。要了解这些IP实际上是什么,可以使用Windows的命令行ipconfig
工具。或者,在服务器代码中,可以使用或API
如果您的客户端与服务器应用程序运行在同一台PC/网络上,它可以直接连接到服务器正在侦听的任何本地/LAN IP。但是,如果客户端运行在不同的网络上(即,在Internet上的另一台PC上),则它需要连接到您的公共IP。并且在该公共IP属于网络路由器的情况下,路由器需要被配置为将给定:
上的入站连接转发到服务器PC的
(即,从113.20.98.124:777
转发到类似192.168.0.1:777
,或实际分配给服务器PC的任何IP)“服务器和客户端都在PC上运行。客户端能否使用PC的IP连接到服务器?”-是。以及链接本地地址127.0.0.1(IPv4)或::1(IPv6)。如果您的路由器中没有静态IP和端口转发,它将无法工作。请高兴!否则您的系统将向世界开放。@ArminMontigny这么说我的IP不是静态的?当您找到“您的IP”时,我如何判断它是否是静态的?(我也不理解“端口转发”部分)“,您没有找到客户端或服务器的IP地址,您找到了路由器的公共IP地址。在您最喜欢的搜索引擎中输入“端口转发”。@DavidSchwartz:除非路由器支持夏萍NAT,否则端口转发也不会有帮助,这在消费者级设备中是很少见的。“服务器和客户端都在PC上运行。客户端可以使用I
#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;
}