0

我有一个服务器和客户端类,但问题是:当我进行无限循环以接受传入连接时,我在接受连接时无法接收从客户端接收到的所有数据,因为接受阻塞直​​到连接被接受,我的代码:

    for (;;) 
    {
       boost::thread thread(boost::bind(&Irc::Server::startAccept, &s));
       thread.join();
       for (ClientsMap::const_iterator it = s.begin(); it != s.end(); ++it) 
       {
          std::string msg = getData(it->second->recv());
          std::clog << "Msg: " << msg << std::endl;
       }
    }
4

3 回答 3

3

您需要多个线程或调用select/poll来找出哪些连接有未处理的数据。 IBM 在这里有一个很好的例子,它适用于任何风格的 Unix、Linux、BSD 等(您可能需要不同的头文件,具体取决于操作系统)。

现在你正在启动一个线程,然后立即等待它,这会导致顺序执行,完全违背了线程的目的。

于 2010-11-13T19:29:39.660 回答
0

一个好的方法是创建一个只接受新连接的线程。那就是你有一个监听器套接字的地方。然后,对于每个被接受的连接,您都有一个新的连接套接字,因此您可以生成另一个线程,将连接的套接字作为参数提供给它。这样,您接受连接的线程就不会被阻塞,并且可以非常快速地连接到许多客户端。处理线程处理客户端,然后它们退出。

我什至不知道为什么需要等待它们,但如果你这样做了,你可能会以其他方式处理它,这取决于你使用的操作系统和/或库(可以使用消息、信号等)。

如果您不想为每个连接的客户端生成一个新线程,那么正如 Ben Voigt 建议的那样,您可以使用 select。如果您想使其成为单线程,这是另一种好方法。基本上,您的所有套接字都将位于套接字描述符数组中,并且使用 select 您将知道发生了什么(有人连接,套接字已准备好读/写,套接字已断开连接等)并采取相应措施。

这是一个部分示例,但它有效。您只需在 acceptConnections() 中接受连接,然后将为每个客户端生成一个单独的线程。那是您与客户沟通的地方。它来自我周围的 Windows 代码,但它很容易在任何平台上重新实现。

typedef struct SOCKET_DATA_ {
  SOCKET sd;
  /* other parameters that you may want to pass to the clientProc */
} SOCKET_DATA;

/* In this function you communicate with the clients */
DWORD WINAPI clientProc(void * param)
{
    SOCKET_DATA * pSocketData = (SOCKET_DATA *)param;

    /* Communicate with the new client, and at the end deallocate the memory for
       SOCKET_DATA and return.
    */

    delete pSocketData;
    return 0;
}

int acceptConnections(const char * pcAddress, int nPort)
{
    sockaddr_in sinRemote;
    int nAddrSize;
    SOCKET sd_client;
    SOCKET sd_listener;
    sockaddr_in sinInterface;
    SOCKET_DATA * pSocketData;
    HANDLE hThread;

    sd_listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (INVALID_SOCKET == sd_listener) {
        fprintf(stderr, "Could not get a listener socket!\n");
        return 1;
    }

    sinInterface.sin_family = AF_INET;
    sinInterface.sin_port = nPort;
    sinInterface.sin_addr.S_un.S_addr = INADDR_ANY;

    if (SOCKET_ERROR != bind(sd_listener, (sockaddr*)&sinInterface, sizeof(sockaddr_in))) {
        listen(sd_listener, SOMAXCONN);
    } else {
        fprintf(stderr, "Could not bind the listening socket!\n");
        return 1;
    }

    while (1)
    {
        nAddrSize = sizeof(sinRemote);
        sd_client = accept(sd_listener, (sockaddr*)&sinRemote, &nAddrSize);

        if (INVALID_SOCKET == sd_client) {
            fprintf(stdout, "Accept failed!\n");
            closesocket(sd_listener);
            return 1;
        }

        fprintf(stdout, "Accepted connection from %s:%u.\n", inet_ntoa(sinRemote.sin_addr), ntohs(sinRemote.sin_port));
        pSocketData = (SOCKET_DATA *)malloc(sizeof(SOCKET_DATA));

        if (!pSocketData) {
            fprintf(stderr, "Could not allocate memory for SOCKET_DATA!\n");
            return 1;
        }

        pSocketData->sd = sd_client;
        hThread = CreateThread(0, 0, clientProc, pSocketData, 0, &nThreadID);

        if (hThread == INVALID_HANDLE_VALUE) {
            fprintf(stderr, "An error occured while trying to create a thread!\n");
            delete pSocketData;
            return 1;
        }
    }

    closesocket(sd_listener);
    return 0;
}
于 2010-11-13T19:49:40.247 回答
0

看看这里: http: //www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/examples.html

特别是HTTP Server 3示例,这正是您正在寻找的,您所要做的就是根据您的需要稍微更改该代码 :) 并完成

于 2010-11-13T20:41:48.613 回答