为什么我的 socket.makefile 对象即使在关闭后也会阻塞? [英] Why does my socket.makefile object block even after a close?

查看:59
本文介绍了为什么我的 socket.makefile 对象即使在关闭后也会阻塞?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我使用 socket.makefile 然后关闭文件对象以及底层套接字,然后对 read 的后续调用将抛出异常,正如我希望的那样.例如,以下代码按我的预期工作:

If I use socket.makefile and then close the file object as well as the underlying socket, then subsequent calls to read will throw an exception, just as I'd want it to. For example, the following code works as I'd expect:

import socket
from time import sleep
from threading import Thread

ADDR = ("localhost", 4321)

def listener(sock):
    client,addr = sock.accept()
    sleep(1)
    client.close()
    sock.close()

server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind(ADDR)
server_sock.listen(1)
Thread(target=listener, args=[server_sock]).start()

sock = socket.create_connection(ADDR)
f = sock.makefile("r+b", bufsize=0)

f.close()
sock.close()
f.read(8)    # throws an exception, as I'd expect

但是,如果我在文件/套接字仍处于打开状态时调用 read 则该调用将阻塞,并且 然后 如果我关闭套接字,则读取方法仍然没有返回.事实上,它会无限期地挂起,直到套接字在另一端关闭.以下代码演示了这种令人痛苦的行为:

However, if I make a call to read while the file/socket are still open then that call will block, and then if I close the socket, the read method still doesn't return. In fact, it hangs indefinitely until the socket is closed on the other end. The following code demonstrates this distressing behavior:

import socket
from time import sleep
from threading import Thread

ADDR = ("localhost", 4321)

def reader(f):
    print("about to read")
    print("we read %r" % f.read(8))
    print("finished reading")

def listener(sock):
    client, addr = sock.accept()
    sleep(3)
    client.close()
    sock.close()

server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind(ADDR)
server_sock.listen(1)
Thread(target=listener, args=[server_sock]).start()

sock = socket.create_connection(ADDR)
f = sock.makefile("r+b", bufsize=0)
Thread(target=reader, args=[f]).start()

sleep(1)
print("closing pseudo-file and socket")
f.close()
sock.close()
sleep(1)
print("we still haven't finished reading!")

这对我来说是一个严重的问题,因为我想在线程中对 f.read 进行阻塞调用,但仍然能够关闭套接字并让线程返回从那个调用(可能通过抛出异常)并退出.然而,所有发生的事情是,只要另一方从不关闭套接字,调用就会永远阻塞.

This is a serious problem for me, since I'd like to make a blocking call to f.read in a thread, but then still be able to close the socket and have the thread return from that call (possibly by throwing an exception) and exit. However, all that happens is that the call blocks forever so long as the other side never closes the socket.

那么Thread1 有没有办法在socket.makefile 创建的类文件对象上调用read,然后让Thread2 以导致 Thread1 在其 read 调用上停止阻塞的方式关闭套接字?

So is there any way for Thread1 to call read on the file-like object created by socket.makefile and then have Thread2 shut down the socket in a way that causes Thread1 to stop blocking on its read call?

我尝试重新编写我的程序以完全使用 gevent 及其套接字和 Greenlet 方法来处理多线程,但我的程序仍然执行完全相同的操作:

I tried re-writing my program to entirely use gevent and its socket and Greenlet approach to multithreading, but my program still does exactly the same thing:

from gevent import sleep, socket, spawn

ADDR = ("localhost", 4321)

def reader(f):
    print("about to read")
    print("we read %r" % f.read(8))
    print("finished reading")

def listener(sock):
    client, addr = sock.accept()
    sleep(3)
    client.close()
    sock.close()

server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind(ADDR)
server_sock.listen(1)
spawn(listener, server_sock)

sock = socket.create_connection(ADDR)
f = sock.makefile("r+b", bufsize=0)
spawn(reader, f)

sleep(1)
print("closing pseudo-file and socket")
f.close()
sock.close()

sleep(1)
print("we still haven't finished reading!")
sleep(2)

我惊讶地发现,即使使用 gevent 套接字,即使在底层套接字关闭后,对 read 的调用也会阻塞.如果没有办法阻止这种情况,我可能只需要接受托马斯令人沮丧的这是不可能的"回答:(

I was surprised to learn that even using gevent sockets, calls to read will block even after the underlying socket is closed. If there's no way to prevent this, I'll probably just have to accept Thomas' depressing "this is not possible" answer :(

推荐答案

是的,线程具有令人烦恼的行为,尤其是在同时从多个线程触摸套接字之类的东西时.这不是您可以使工作正常进行的事情.没有办法强制一个在读取中被阻塞的线程中断读取或终止——从它下面关闭套接字更有可能导致你的整个程序出现段错误(或更糟)而不是执行你的操作想要.

Yes, threads have distressing behaviour, especially when touching things like sockets from multiple threads at the same time. This is not something you can make work right. There is no way to force a thread that's blocked in a read to break out of the read or terminate -- closing the socket from under it is more likely to cause your entire program to segfault (or worse) than it is to do what you want.

处理这种情况的正确方法是使用非阻塞读取.像 Twisted 这样合适的事件框架可以帮助您解决这个问题.

The right way to deal with situations like this is to use non-blocking reads, instead. A decent event framework, like Twisted, can help you with this.

这篇关于为什么我的 socket.makefile 对象即使在关闭后也会阻塞?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆