在 C++ 中使用 TCP 套接字进行远程客户端和服务器通信

Remote client and server communication using TCP sockets in c++

我想 运行 服务器和客户端使用远程套接字编程(来自我的电脑的客户端和远程主机上的服务器)。我用 C++ 编写了一个程序,它在本地机器上 运行s,包括客户端和服务器。现在我如何 运行 来自不同机器的服务器?在 server.cpp 中,我使用了 INADDR_ANY,我不知道如何将我的 PC(在哪个服务器上 运行ning)的 IP 地址提供给客户端和 ip 地址个人电脑(我有我的客户端程序)到服务器。客户端和服务器是否具有相同的端口号,或者它们也可以具有不同的端口号?如果是,那我该如何分配?

server.cpp

#include <iostream>
#include <WS2tcpip.h>
#include <string>
#include <cstdlib>
#pragma comment (lib, "ws2_32.lib")

using namespace std;

void main()
{

    WSADATA data;
    WORD ver = MAKEWORD(2, 2);

    int wres = WSAStartup(ver, &data);
    if (wres != 0)
    {
        cerr << "unable to initialize winsock" << endl;
        return;
    }


    SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
    if (listening == INVALID_SOCKET)
    {
        cerr << "unable to create a socket" << endl;
        return;
    }

    sockaddr_in sdata;
    sdata.sin_family = AF_INET;
    sdata.sin_port = htons(54000);
    sdata.sin_addr.S_un.S_addr = INADDR_ANY;

    bind(listening, (sockaddr*)&sdata, sizeof(sdata));

    listen(listening, SOMAXCONN);


    sockaddr_in client;
    int csize = sizeof(client);

    SOCKET clientsock = accept(listening, (sockaddr*)&client, &csize);

    char host[NI_MAXHOST];
    char service[NI_MAXSERV];

    ZeroMemory(host, NI_MAXHOST);
    ZeroMemory(service, NI_MAXSERV);

    if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
    {
        cout << host << " connected on port " << service << endl;
    }
    else
    {
        inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
        cout << host << " connected on port " <<
            ntohs(client.sin_port) << endl;
    }
    //listening
    closesocket(listening);
    

    char buf[4096];
    //char temp[] = "Hello";
    //char *input = temp;
    string input;
    int inputsize;
    while (true)
    {
        ZeroMemory(buf, 4096);


        int recbyte = recv(clientsock, buf, 4096, 0);
        if (recbyte == SOCKET_ERROR)
        {
            cerr << "Error in recv(). Quitting" << endl;
            break;
        }

        if (recbyte == 0)
        {
            cout << "Client disconnected " << endl;
            break;
        }
        cout << "Client>";
        cout << string(buf, 0, recbyte) << endl;
         
        cout << "> ";
        getline(cin, input);


        send(clientsock, input.c_str(), input.size() + 1, 0);

    }


    closesocket(clientsock);

    WSACleanup();

    system("pause");
}

client.cpp

#include <iostream>
#include <string>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")

using namespace std;

void main()
{
    string ipAddress = "127.0.0.1";         
    int port = 54000;                       

    WSAData data;
    WORD ver = MAKEWORD(2, 2);
    int wsResult = WSAStartup(ver, &data);
    if (wsResult != 0)
    {
        cerr << "Can't start Winsock, Err #" << wsResult << endl;
        return;
    }

    
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET)
    {
        cerr << "Can't create socket, Err #" << WSAGetLastError() << endl;
        WSACleanup();
        return;
    }

    sockaddr_in hint;
    hint.sin_family = AF_INET;
    hint.sin_port = htons(port);
    inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);


    int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
    if (connResult == SOCKET_ERROR)
    {
        cerr << "Can't connect to server, Err #" << WSAGetLastError() << endl;
        closesocket(sock);
        WSACleanup();
        return;
    }

    
    char buf[4096];
    string userInput;

    do
    {
        
        cout << "> ";
        getline(cin, userInput);

        if (userInput.size() > 0)       
        {

            int sendResult = send(sock, userInput.c_str(), userInput.size() + 1, 0);
            if (sendResult != SOCKET_ERROR)
            {
                
                ZeroMemory(buf, 4096);
                int bytesReceived = recv(sock, buf, 4096, 0);
                if (bytesReceived > 0)
                {
                    
                    cout << "SERVER> " << string(buf, 0, bytesReceived) << endl;
                }
            }
        }

    } while (userInput.size() > 0);

    closesocket(sock);
    WSACleanup();
}

我认为您没有完全理解 client-server 的作用。 服务器不知道、不能也不应该知道连接到它的客户端的地址(尽管它可以在连接后知道)。 要完成连接,客户端需要知道它们应该连接到的 IP 和端口,并且服务器应该将其服务器端口(它侦听的端口)绑定到正确的 IP 和端口。 默认 IP 通常使用 INADDR_ANY 表示,在大多数情况下这是可以的,但是如果机器上有多个地址,您可能必须指定另一个地址。 客户端通常不绑定它们的连接套接字,因为它们自己的端口号并不重要。他们自己的 IP 也不重要,因为在连接期间不使用它。 因此,您应该做的是 运行 在您的 PC 上安装您的服务器应用程序,并将您的 PC 地址和端口号提供给所有寻求连接到您的客户端。