套接字关闭后c ++ linux accept()阻塞

Bra*_*ner 5 c++ sockets linux blocking

我有一个侦听新连接的线程

new_fd = accept(Listen_fd, (struct sockaddr *) & their_addr, &sin_size);
Run Code Online (Sandbox Code Playgroud)

和另一个在关闭程序时关闭Listen_fd的线程.然而,在Listen_fd关闭后,它仍然会阻塞.当我使用GDB尝试和调试时,accept()不会阻塞.我认为这可能是SO_LINGER的问题,但默认情况下它不应该打开,并且在使用GDB时不应该更改.有什么想法,或关闭列表套接字的任何其他建议?

Bor*_*lid 6

accept调用不是有效套接字FD的东西时的行为是未定义的."不是有效的套接字FD"包括曾经是有效套接字但后来被关闭的数字.您可能会说"但Borealid,它应该返回EINVAL!",但这并不能保证 - 例如,相同的FD号码可能会重新分配给您closeaccept呼叫之间的不同套接字.

因此,即使您要隔离并纠正使程序失败的任何原因,您将来仍可能再次失败.不要这样做 - 纠正导致您尝试accept在已关闭的套接字上建立连接的错误.

如果你的意思是之前做过的呼叫accept 继续阻塞close,那么你应该做的是向阻塞的线程发送一个信号accept.这将使它EINTR并且它可以干净地脱离 - 然后关闭插座.请勿从使用它的线程以外的线程中关闭它.


mpb*_*mpb 5

使用: sock.shutdown (socket.SHUT_RD)

然后accept将返回EINVAL。无需丑陋的交叉螺纹信号!

在Python文档中:“ Note close()释放与连接关联的资源,但不一定立即关闭连接。如果要及时关闭连接,请shutdown()在之前调用close()。”

http://docs.python.org/3/library/socket.html#socket.socket.close

几年前,我在用C语言编程时遇到了这个问题。但是,直到在Python中遇到相同的问题,并思考使用信号(糟糕!)之后,我才找到了解决方案,然后记住了有关shutdown

至于说不应该关闭/使用线程间套接字的注释……在CPython中,全局解释器锁应该为您提供保护(假设您使用的是文件对象,而不是原始的整数文件描述符)。

这是示例代码:

import socket, threading, time

sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind (('', 8000))
sock.listen (5)

def child ():
  print ('child  accept ...')
  try:  sock.accept ()
  except OSError as exc :  print ('child  exception  %s' % exc)
  print ('child  exit')

threading.Thread ( target = child ).start ()

time.sleep (1)
print ('main   shutdown')
sock.shutdown (socket.SHUT_RD)

time.sleep (1)
print ('main   close')
sock.close ()

time.sleep (1)
print ('main   exit')
Run Code Online (Sandbox Code Playgroud)

  • 我有一个C ++程序,该程序在主线程中打开一个侦听套接字,并生成一个子线程来接受传入的连接。主线程需要在接收到信号后关闭接收器线程。close(s)不起作用,因为`accept(…)`继续在封闭的套接字上阻塞,但是`shutdown(s,SHUT_RD)`使`accept(...)`立即以`EINVAL`保释。完美的解决方案,即使在关闭发生时接受器线程位于对`accept(…)`的调用之间,该方法也能正常工作。谢谢! (2认同)

Kar*_*ath 1

这是一种解决方法,但您可以select设置Listen_fd超时,如果发生超时,请检查是否要关闭程序。如果是,则退出循环,如果不是,则返回步骤1,执行下一步select