c++ - 如何在 Windows - Visual Studio 上用 C++ 将多个客户端连接到单个服务器?

标签 c++ multithreading sockets

我用C++编写了一个服务器程序,也用C++编写了一个客户端程序。 两者都工作正常,但是当一个客户端与服务器通信时,其他客户端无法连接到同一服务器。如果假设当我关闭客户端 1 时,我的第二个客户端也无法连接到服务器。我已使用多个线程启动服务器来连接到多个客户端,但只有一个客户端正在连接。

我的服务器程序:

#include <iostream>
#include <winsock2.h>
#include <Windows.h>
#include <process.h>
#include <thread>
#pragma comment(lib,"ws2_32.lib")

static const int num_of_threads = 2;

void client_disconnected(SOCKET Socket);

void start_server()
{
    WSADATA WsaDat;
    if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
    {
        std::cout<<"WSA Initialization failed!\r\n";
        WSACleanup();
        system("PAUSE");
    }

    SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(Socket==INVALID_SOCKET)
    {
        std::cout<<"Socket creation failed.\r\n";
        WSACleanup();
        system("PAUSE");
    }

    SOCKADDR_IN serverInf;
    serverInf.sin_family=AF_INET;
    serverInf.sin_addr.s_addr=INADDR_ANY;
    serverInf.sin_port=htons(8888);

    if(bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf))==SOCKET_ERROR)
    {
        std::cout<<"Unable to bind socket!\r\n";
        WSACleanup();
        system("PAUSE");
    }

    listen(Socket,3);

    SOCKET TempSock=SOCKET_ERROR;
    while(TempSock==SOCKET_ERROR)
    {
        std::cout<<"Waiting for incoming connections...\r\n";
        Sleep(5000);    
        TempSock=accept(Socket,NULL,NULL);
    }

    // If iMode!=0, non-blocking mode is enabled.
    u_long iMode=1;
    ioctlsocket(Socket,FIONBIO,&iMode);

    Socket=TempSock;
    std::cout<<"Client connected!\r\n\r\n";

    // Main loop
    for(;;)
    {
        int nError=WSAGetLastError();
        if(nError!=WSAEWOULDBLOCK&&nError!=0)
        {
            client_disconnected(Socket);
            break;
        }
        char *szMessage="Welcome to the server!\r\n";
        send(Socket,szMessage,strlen(szMessage),0);
        Sleep(2000);            
    }
}
void client_disconnected(SOCKET Socket)
{
    std::cout<<"Client disconnected!\r\n";

    // Shutdown our socket
    shutdown(Socket,SD_SEND);

    // Close our socket entirely
    closesocket(Socket);

    WSACleanup();
}


int main()
{
   //starting multiple threads for invoking server

    std::thread threads[num_of_threads];
    //This statement will launch multiple threads in loop
    for (int i = 0; i < num_of_threads; ++i) {
        threads[i] = std::thread(start_server);
        Sleep(2000);
    }

    for (int i = 0; i < num_of_threads; ++i) {
        threads[i].join();
    }
    return 0;

}

我的客户计划:

#include <iostream>
#include <winsock2.h>
#include <Windows.h>
#include <process.h>
#include "client.h"
#pragma comment(lib,"ws2_32.lib") 


void MultipleClient :: receiveToClient(void*data)
{
    WSADATA WsaDat;
    if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
    {
        std::cout<<"Winsock error - Winsock initialization failed\r\n";
        WSACleanup();
        system("PAUSE");

    }

    // Create our socket

    SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(Socket==INVALID_SOCKET)
    {
        std::cout<<"Winsock error - Socket creation Failed!\r\n";
        WSACleanup();
        system("PAUSE");

    }

    // Resolve IP address for hostname
    struct hostent *host;
    if((host=gethostbyname("localhost"))==NULL)
    {
        std::cout<<"Failed to resolve hostname.\r\n";
        WSACleanup();
        system("PAUSE");

    }

    // Setup our socket address structure
    SOCKADDR_IN SockAddr;
    SockAddr.sin_port=htons(8888);
    SockAddr.sin_family=AF_INET;
    SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr);

    // Attempt to connect to server
    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr))!=0)
    {
        std::cout<<"Failed to establish connection with server\r\n";
        WSACleanup();
        system("PAUSE");

    }

    // If iMode!=0, non-blocking mode is enabled.
    u_long iMode=1;
    ioctlsocket(Socket,FIONBIO,&iMode);

    // Main loop
    for(;;)
    {
        // Display message from server
        char buffer[1000];
        memset(buffer,0,999);
        int inDataLength=recv(Socket,buffer,1000,0);
        std::cout<<buffer;

        //end client when server is disconnected
        int nError=WSAGetLastError();
        if(nError!=WSAEWOULDBLOCK&&nError!=0)
        {
            std::cout<<"Winsock error code: "<<nError<<"\r\n";
            std::cout<<"Server disconnected!\r\n";
            // Shutdown our socket
            shutdown(Socket,SD_SEND);

            // Close our socket entirely
            closesocket(Socket);

            break;
        }
        Sleep(2000);
    }

    WSACleanup();
    system("PAUSE");

}

class Client{
        public:
    static unsigned int __stdcall receiveMessageThread(void *p_this)
        {
            MultipleClient* mc = static_cast<MultipleClient*>(p_this);
            mc-> receiveToClient(p_this); // Non-static member function!
            return 0;
        }
    void startThread()
    {
        HANDLE myhandleA;
            myhandleA = (HANDLE)_beginthreadex(0,0,&Client::receiveMessageThread,this,0, 0);
            WaitForSingleObject(myhandleA, INFINITE);
    }
    };
    int main(void)
    {

        Client *c = new Client;
        c->startThread();

        return 0;
    }

请帮助我如何使多个客户端连接到单个服务器。示例代码将非常有用(抱歉询问)。

最佳答案

您在线程之间分配工作的方式是错误的。

您希望一个线程打开监听套接字并在那里等待传入连接。请注意,每个端口不能有多个监听套接字,因此您绝对不希望多个线程同时尝试监听同一端口。

如果有连接进入,accept将为您提供一个新的套接字对象。您仍然拥有原来的监听套接字,它等待新连接,但您现在还有一个第二套接字,该套接字已与客户端建立连接。

现在您可以拆分工作:让一个线程返回到在原始套接字上调用 listen 并等待新连接,而另一个线程则获取新套接字并执行必要的 I/O与客户互动。

在这个简单的方案中,每个客户端连接始终有一个线程,另外还有一个用于监听套接字的线程。由于所有这些线程都会花费大量时间等待网络 I/O 完成,因此您可以使用异步 I/O 在更少(甚至单个)线程之间分担工作负载,但这稍微复杂一些完成,所以我建议你把它留到第二稿。

关于c++ - 如何在 Windows - Visual Studio 上用 C++ 将多个客户端连接到单个服务器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42643276/

相关文章:

c++ - 现代 C++ 实现具有可变数量的 int 参数的函数的最佳方法

c++ - 在测试主体中抛出代码 0xc0000005 的 SEH 异常

c++ - 应用程序退出时线程无法退出 - C++

c++ - 在 C++ 中执行跨平台线程间通知的好方法是什么?

c# - 如何在 C# TCP/IP 中的 Socket.Connect 中传递用户名和密码

c++ - 使用 rdbuf()->sputn(...) 与运算符<<

c++ - 与 Mergesort 相比,为什么 GNU 并行快速排序这么慢?

java - Java 中的类变量是否在线程之间共享?

python - UDP 聊天,服务器也可以聊天

sockets - 了解WebSockets