首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >服务器和客户端都运行在PC上。客户端可以使用PC的IP连接到服务器吗?

服务器和客户端都运行在PC上。客户端可以使用PC的IP连接到服务器吗?
EN

Stack Overflow用户
提问于 2019-07-07 12:08:34
回答 1查看 347关注 0票数 0

我对网络编程很陌生,所以这件事困扰了我好几天。

我写了两个应用程序:一个是服务器,一个是客户端。

我想让他们做的是:当我向客户机提供IP地址时,客户机将用所提供的IP连接到机器上的服务器。

我通过在我的PC上打开服务器和客户端来测试它,输入回环地址(127.0.0.1)。连接到服务器的客户端很好(我甚至可以互相发送短信)。

所以我再试一试。我在谷歌上搜索了我的IP (即113.20.98.124),然后将其输入到我的客户端。我预计客户端也会连接到服务器,但这并没有发生。客户端终止连接超时(WSAETIMEDOUT 10060)。

我想问的是:为什么我不能使用我的IP告诉客户端连接到我的服务器?这算是件事吗?

以下是服务器和客户端的代码(万一我做错了什么):

(我在Windows上使用VS2017编写代码)

客户端:

代码语言:javascript
复制
#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;
}

服务器:

代码语言:javascript
复制
#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/

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-07-07 18:45:41

当你在谷歌上搜索你的IP时,你得到了你的公共IP,就像外界看到的那样。如果你的电脑是直接连接到你的互联网调制解调器,那么这个IP属于你的电脑。但是,如果你的个人电脑在网络路由器后面(这在现在有很多互联网连接设备的家庭中很常见),那么这个IP就属于你的网络路由器,而不是你的个人电脑。

您的服务器应用程序只能在本地/LAN is上侦听,这些is直接分配给正在运行的PC。如果该PC运行在网络路由器后面,它就无法侦听路由器的公共IP。

您的服务器代码正在绑定其侦听套接字,以便它侦听分配给正在运行的PC的所有可用的IPv4 IP。要了解这些IP到底是什么,您可以使用Windows的命令行ipconfig工具。或者,在服务器代码中,可以使用GetAdaptersInfo()GetAdaptersAddresses() API。

如果您的客户端运行在与服务器应用程序相同的PC/网络上,它可以直接连接到服务器正在监听的任何本地/LAN IP。但是,如果客户端运行在不同的网络(即,在另一台PC上通过Internet),它需要连接到您的公共IP。如果该公共IP属于网络路由器,则需要将路由器配置为将给定<PublicIP>:<PublicPort>上的入站连接转发到服务器PC的<LanIP:LanPort> (即从113.20.98.124:777转发到类似于192.168.0.1:777的东西,或者任何实际分配给服务器PC的IP )。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56922023

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档