正确的方法来关闭阻塞的UDP套接字

时间:2011-06-10 11:03:41

标签: c++ sockets

我有一个C ++对象,它创建一个线程来从阻塞的UDP套接字中读取:

mRunning.store(true);
while (mRunning.load(boost::memory_order_consume)) {
    ...
    int size = recvfrom(mSocket, buf, kTextBufSize , 0,
                        (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen);

    if (size > 0) {
        //do stuff
    }
}
return 0;

(mRunning是一个提升::原子) 从另一个线程调用对象的析构函数并执行此操作:

mRunning.store(false);  
#ifdef WIN32
    if (mSocket != -1) closesocket(mSocket);
#else
    if (mSocket != -1) close(mSocket);
#endif
pthread_join(mThread, NULL);

这似乎有效,但我的一位同事建议,如果recv在阅读过程中被中断,可能会出现问题。这个线程安全吗?关闭阻塞UDP套接字的正确方法是什么? (需要跨平台的OSX / Linux / Windows)

3 个答案:

答案 0 :(得分:5)

可能会有很多不同的问题。将我的应用程序从一个FreeBSD版本移动到另一个版本我发现这样的close()在旧内核上正常工作,只是挂起close()直到从较新的recv()返回的东西。 OSX基于FreeBSD:)

从不同线程关闭套接字的便携方式是创建管道和块而不是在recv()中,而是在select()中。当你需要关闭套接字时,写一些东西到管道,select()将解除阻塞,你可以安全地关闭()。

答案 1 :(得分:1)

recvfrom本身 是线程安全的。 IIRC所有套接字功能都是。问题是:

  • 如果在将数据复制到缓冲区时从recvfrom下拉取描述符,会发生什么?

这是一个好问题,但我怀疑标准是否说明了这一点(我也怀疑实施的具体手册说明了一切)。所以任何实现都是免费的:

  • 完成操作(也许是因为它不再需要描述符,或者因为它正在进行一些很酷的引用计数或其他事情)
  • recvfrom失败并返回-1ENOTSOCKEINVAL?)
  • 崩溃引人注目,因为close释放了缓冲区和内部数据结构。

显然这只是猜测(以前我错了很多次),但除非您在标准中找到某些内容以支持您可以在接收套接字时关闭套接字的想法, “不安全。

那么,你能做什么?最安全的:使用同步机制确保在close完成后只有recvfrom套接字(信号量,互斥量,等等)。

就个人而言,我会在UP之后的信号量recvfrom以及DOWN之前的close。{/ p>

答案 2 :(得分:0)

你的同事是对的,提升套接字不是线程安全的。

您的选择;

  1. 使用ASIO(执行此操作)
  2. 阻止通话超时。虽然它可能有用,但它并不是真正可移植的。