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

赫马钱德拉

我用 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;
    }

请帮助我如何使多个客户端与单个服务器连接。示例代码将非常有用(对不起,问)。

ComicSansMS

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

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

如果一个连接进来,accept会给你一个新的套接字对象。您仍然拥有等待新连接的原始侦听套接字,但您现在还有第二个套接字,其中已建立与客户端的连接。

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

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在Windows上为C ++配置Visual Studio Code?

如何在Windows和CMake上使用Visual Studio编译Mac OS X的C ++

使用终端服务客户端连接到Windows服务器时,如何启用字体平滑?

如何使用 Visual Studio 编译器在 Windows 上编译 cython 编译的 c 代码

如何在Windows Visual Studio上使用SQL更新表

如何将android客户端连接到用C编写的服务器?

如何将客户端连接到不同网络上的服务器?

如何在Mac上的Windows上编译C#Visual Studio解决方案

如何在CentOS服务器上使用YUM在多个客户端上安装Windows更新

如何在Windows 10上使用Visual Studio 2015 x64配置和构建Tesseract OCR C ++

多个客户端如何同时连接到服务器上的一个端口(例如80)?

Linux原生C库:如何配置Visual Studio Code以在Windows上使用它们?

如何在 ubuntu 上运行我在 Windows for Linux 上使用 Visual Studio 编译的文件

如何在Visual Studio 2015中使用Clang为Windows编译C ++

如何在Visual Studio for Mac上开发Windows应用

使用C ++ API使用加密通道将mq客户端连接到mq服务器

如何通过Visual Studio中的客户端javascript项目访问服务器的webapi项目

如何使用url将python套接字客户端连接到服务器套接字?

如何使用Visual Studio 2017在Windows上构建OpenSSL?

如何从Visual Studio Code集成终端在Windows上使用Bash?

如何使用C ++中的Websocket客户端将消息发送到服务器?

只能使用c中的客户端连接到服务器一次

如何使用 Visual Studio 连接到 Azure SQL 服务器

如何在Visual Studio 2015上使用NuGet软件包管理器为C#安装NUnit

如何在没有Visual Studio的Windows上安装Leptonica + tesseract以在Anaconda中使用?

如何在Windows下使用cmake生成使用Intel编译器的Visual Studio项目

在C中使用单个服务器程序的多个客户端(TCP)

Java RMI客户端如何使用域名连接到Java RMI服务器

客户端如何使用EC2连接到服务器