【问题标题】:Gracefully stop socket during blocking call to socket.recv()在阻塞调用 socket.recv() 期间优雅地停止套接字
【发布时间】:2019-05-30 20:23:24
【问题描述】:

我有一个在 2 个线程上运行的程序。主线程自己工作,另一个线程在 UDP 套接字上不断调用recv()

基本上,代码结构是这样的:

done = False

def run_sock():
   sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   sock.bind(('localhost', 12345))
   while not done:  # receive data until work done
        data = sock.recv(1500)
        print(data)
   sock.close()

thread = threading.Thread(target=run_sock, daemon=True)
thread.start()

# Main thread
while not done:
    ... # Do work here
    if some_condition:  # Stop running, thread should as well
        done = True

thread.join()

我想在主线程将done 更改为True 时关闭套接字,但是当这种情况发生时,套接字仍处于其当前阻塞recv 调用中,它必须在最终停止之前接收另一条消息.

有没有办法优雅地关闭套接字(无需处理错误)?我试过sock.shutdown(socket.SHUT_RDWR)sock.setblocking(False),但它们都会引发错误。

【问题讨论】:

  • miiiiight 想使用互斥锁或类似的线程安全结构在线程之间进行通信
  • @Will 这只是我目前正在研究的一个过于简化的版本。我不想要任何冗余代码,因为我认为线程安全不是这里的问题
  • sock.recv(1500) 如果它没有获取数据应该永远阻塞,所以done 永远不会被检查并且 sock.close() 永远不会被调用
  • 是的,这就是我的问题所在。

标签: python sockets udp


【解决方案1】:

所以sock.recv(1500) 将阻塞直到它收到一些东西。如果它什么也没收到,那么它会等待。

但是,如果您设置了超时,那么该等待会定期抛出异常,您可以在尝试再次读取之前执行其他操作(例如查看 done 标志)。

sock.settimeout(1.0)
sock.bind(...)

while not done:
    try:
        data = sock.recv(1500)
    except timeout:
        continue
sock.close()

当然,如果远端关闭连接就不同了。那你需要查看data看是否为空。

while not done:
    try:
        data = sock.recv(1500)
        if not data:
            break
    except timeout:
        continue

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-11
    • 1970-01-01
    • 2016-02-01
    • 2012-03-16
    • 1970-01-01
    • 2020-05-23
    • 1970-01-01
    • 2018-01-20
    相关资源
    最近更新 更多