停止在recv上阻塞的接收器线程()

我有一个聊天应用程序,它有一个单独的线程来监听传入的消息。

while (main thread not calling for receiver to quit) { string message = tcpCon.tcpReceive(); // Relies on the recv() function processIncomingMessage(message); } 

这种工作方式有一个大问题。 大多数情况下,循环将在recv()上阻塞,因此接收器线程不会退出。 在几秒钟后不强制线程终止的情况下解决此问题的正确方法是什么?

使用shutdown()关闭套接字以shutdown()所有接收器。

这会在我的系统上输出’recv return 0’,表明接收器看到了有序关机。 注释掉shutdown()并观察它永远挂起。

从长远来看,OP应该使用select或在协议中包含显式退出消息来修复设计。

 #include  #include  #include  #include  #include  #include  /* Free on my system. YMMV */ int port = 7777; int cd; void *f(void *arg) { /* Hack: proper code would synchronize here */ sleep(1); /* This works: */ shutdown(cd, SHUT_RDWR); close(cd); return 0; } int main(void) { /* Create a fake server which sends nothing */ int sd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in sa = { 0 }; const int on = 1; char buf; pthread_t thread; sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl(INADDR_ANY); sa.sin_port = htons(port); setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); /* Other error reporting omitted for clarity */ if (bind(sd, (const struct sockaddr*)&sa, sizeof sa) < 0) { perror("bind"); return EXIT_FAILURE; } /* Create a client */ listen(sd, 1); cd = socket(AF_INET, SOCK_STREAM, 0); connect(cd, (const struct sockaddr*)&sa, sizeof sa); accept(sd, 0, 0); /* Try to close socket on another thread */ pthread_create(&thread, 0, f, 0); printf("recv returned %d\n", recv(cd, &buf, 1, 0)); pthread_join(thread, 0); return 0; } 

您可以使用select()等待传入数据并避免在recv()中阻塞。 select()也会阻塞,但你可以在设定的时间间隔后让它超时,这样while循环可以继续并检查从主线程退出的信号:

 while (main thread not calling for receiver to quit) { if (tcpCon.hasData(500)) { // Relies on select() to determine that data is // available; times out after 500 milliseconds string message = tcpCon.tcpReceive(); // Relies on the recv() function processIncomingMessage(message); } } 

如果在另一个线程中关闭套接字,则recv()将退出。

从任何其他线程调用socket上的close将使recv调用立即失败。