C++多线程TCP服务器问题

4
我正在编写一个简单的TCP服务器。我想到的模型是服务器在主线程中接受客户端连接,并将它们交给另一个线程,以便服务器可以再次监听连接。下面是我使用的代码的相关部分:
接受连接:
void startServer () {

    int serverSideSocket = 0;
    int clientSideSocket = 0;

    serverSideSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSideSocket < 0) {
        error("ERROR opening socket");
        exit(1);
    }

    clientAddressLength = sizeof(clientAddress);
    memset((char *) &serverAddress, 0, sizeof(serverAddress));
    memset((char *) &clientAddress, 0, clientAddressLength);

    serverAddress.sin_family = AF_INET;
    serverAddress.sin_addr.s_addr = INADDR_ANY;
    serverAddress.sin_port = htons(32000);

    if (bind(serverSideSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
        error("ERROR on binding");
        exit(1);
    }      

    listen(serverSideSocket, SOMAXCONN);

    while(true) {
        clientSideSocket = accept(serverSideSocket, (struct sockaddr *) &clientAddress, &clientAddressLength);

    if (clientSideSocket < 0)
            error("ERROR on accept");

        processingThreadGroup->create_thread(boost::bind(process, clientSideSocket, this));
    }

}

在这里,processingThreadGroup是一个boost::thread_group实例。在process方法中:
void process (int clientSideSocket, DataCollector* collector) {

int numberOfCharactersRead = 0;
string buffer;

do {
      char msgBuffer[1000];
      numberOfCharactersRead = recv(clientSideSocket, msgBuffer, (1000 - 1), 0);
      if (numberOfCharactersRead < 0) {
          //display error
          close(clientSideSocket);
      }
      else if (numberOfCharactersRead == 0)
          close(clientSideSocket);
      else {
          printf("%s", msgBuffer);
          memset(msgBuffer, 0, 1000);
      }
   } while (numberOfCharactersRead > 0); 
}

然而,当我调试代码时,我发现当处理线程被调用时,主线程不再接受连接。数据仅在process()方法中读取。主线程似乎不再运行。我采取的方法有什么问题,有什么建议可以纠正它吗?
编辑:我想我在这里找到了问题,并将其更新为答案。不会接受它,因为我回答了自己的问题。谢谢大家的帮助!

也许你的主线程由于某些原因没有接收到处理器时间。尝试确定主线程卡在哪里。在你感觉主线程被冻结的process中设置断点,查看主线程执行点。 - Rost
第一次看到 'printf("%s", msgBuffer);' 时似乎有点可疑,因为通常情况下没有使用memset()。但是,为什么尝试打印未终止的字符串会影响您的accept()线程,我不知道。不过还是要小心。 - Martin James
大家好,感谢所有的建议。我在主循环中放置了一些调试点,但似乎只有生成的线程在运行。主线程的调试点在第一次后就没有被触发。所有后续的数据都通过第一个接受的连接接收。然而,如果我在打印接收到的数据后关闭客户端套接字,那么下一个连接将再次由主线程指向另一个线程。我不知道为什么会发生这种情况。有什么想法吗? - Izza
这是什么平台?你是否正在生成代码并链接多线程库? - mark
这是在Ubuntu上。我编写了服务器代码。对于一些Thrift文件,还有一个生成的部分,但不属于服务器部分。我正在使用NetBeans C++ IDE,并通过IDE链接Boost库。 - Izza
显示剩余4条评论
1个回答

1

我想我找到了问题所在。我正在使用它作为服务器来接收syslog消息。我用于syslog消息生成器的代码如下:

openlog ("MyProgram", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL0);
cout << "opened the log" << endl;
for (int i = 0 ; i < 10 ; i++) 
{
    syslog (LOG_INFO, "Program started by User %d \n", getuid ());
    syslog (LOG_WARNING, "Beware of the WARNING! \n");
    syslog (LOG_ERR, "fatal ERROR! \n");
}   
closelog ();
cout << "closed the log" << endl;

我在rsyslog.conf文件中使用一个条目来将所有syslog LOG_LOCAL0应用程序流量定向到服务器侦听的相关TCP端口。某种程度上,syslog只允许建立一个而不是多个连接。因此,它仅在单个线程中使用一个连接。如果该连接被关闭,则会创建一个新的连接。

我使用普通的tcp客户端进行了检查。对于每个接受的连接,它都可以正常工作,并生成多个线程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接