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

问题描述

我想使用套接字编程远程运行服务器和客户端(我的PC上的客户端和远程主机上的服务器)。我已经用C ++编写了一个程序,该程序可以在客户端和服务器的本地计算机上运行。现在如何从其他计算机上运行服务器?在server.cpp中,我使用了INADDR_ANY,我不知道如何将我的PC(正在运行该服务器的IP)的IP地址提供给客户端,以及该PC的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,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,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,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,0);
                if (bytesReceived > 0)
                {
                    
                    cout << "SERVER> " << string(buf,bytesReceived) << endl;
                }
            }
        }

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

    closesocket(sock);
    WSACleanup();
}

解决方法

我认为您不完全了解客户端服务器角色。 服务器不但不能也不应该知道连接到它的客户端的地址(尽管在连接后它可以知道)。 为了完成连接,客户端需要知道他们应该连接到的IP和PORT,并且服务器应该将其服务器端口(侦听它的端口)绑定到正确的IP和PORT。 通常使用INADDR_ANY来描述默认IP,在大多数情况下都可以,但是如果计算机上有多个地址,则可能必须指定另一个地址。 客户端通常不绑定其连接套接字,因为它们自己的端口号并不重要。同样,他们自己的IP也不重要,因为在连接过程中不会使用它。 因此,您应该做的是在PC上运行服务器应用程序,并将PC的地址和PORT端口号提供给所有寻求与您连接的客户端。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...