python中的select和ssl
我有一个使用select.select()的服务器应用程序,现在我正试图将SSL添加到该应用程序中,但是在侦听“原始”套接字时出现以下错误: 所以我想我应该使用select中ssl.wrap_套接字返回的ssl流。这样做,它不会返回任何错误,但也不起作用-我不确定问题是什么,我做了很多研究,遇到过类似问题的帖子,但我还没有找到解决方法python中的select和ssl,python,select,ssl,Python,Select,Ssl,我有一个使用select.select()的服务器应用程序,现在我正试图将SSL添加到该应用程序中,但是在侦听“原始”套接字时出现以下错误: 所以我想我应该使用select中ssl.wrap_套接字返回的ssl流。这样做,它不会返回任何错误,但也不起作用-我不确定问题是什么,我做了很多研究,遇到过类似问题的帖子,但我还没有找到解决方法 非常感谢您的帮助。正如马吕斯指出的,select.select()适用于SSL套接字,我仍然不知道是什么导致了我的无声错误,但当我认为这是SSL+select()
非常感谢您的帮助。正如马吕斯指出的,select.select()适用于SSL套接字,我仍然不知道是什么导致了我的无声错误,但当我认为这是SSL+select()时,我就大发雷霆了。因此,这个问题得到了回答。使用带有
select()
的SSL套接字并不像最初看起来那么简单。当你给它一个错误的时候,它不会抛出一个错误,如果你只是像普通的套接字一样使用它们,你迟早会遇到一些奇怪的事情
由于select()
需要一个文件描述符,它将获得原始套接字。但是,即使原始套接字变得可读,这并不意味着您将从SSL套接字中获取数据。您需要使用非阻塞套接字(在使用select()
时这是一个好主意),如果它抛出SSL\u ERROR\u WANT\u READ
(SSL等效于ewoodblock
)
另一个问题是,如果向另一端的连接写入2048个字节,则端上的select()
将返回。但是,如果您只从SSL套接字读取1024个字节,则SSL套接字可能会在内部读取更多数据,并且下一个select()
将不会返回,即使有更多数据要读取,这可能会导致连接死锁。这是因为原始套接字(即select()
正在使用的套接字)没有任何数据,因为它已经在SSL套接字的缓冲区中
首先想到的解决方案是读取更多数据,直到读取抛出SSL\u ERROR\u WANT\u read
,从而清空缓冲区。但是,如果另一端生成数据的速度快于您处理数据的速度,那么在该端完成生成数据之前,您的所有其他连接都将处于饥饿状态
通过调用sslsock.pending()
,您可以看到SSL套接字包含了多少缓冲数据。因此,更好的方法是,首先对一定数量的数据执行一次读取,检查挂起数据的数量,然后对该数量的数据执行第二次读取,从而清空缓冲区而不会导致任何更多的读取
SSL_pending()
(幕后的C函数)的手册页也说明:
SSL_pending()只考虑当前正在处理的TLS/SSL记录中的字节(如果有)。如果设置了SSL对象的read_-ahead标志,则可能已读取包含更多TLS/SSL记录的附加协议字节;这些被SSL_pending()忽略
据我所知,这意味着如果设置了read\u ahead
,则需要重复第二步,直到SSL\u pending()
返回0。我很确定python不会设置read_ahead
,但最好是安全的,而不是抱歉,因此我在示例代码中包含了循环
我对这一点不太熟悉,但像这样的方法应该会奏效:
# Put the SSL socket to non-blocking mode
sslsock.setblocking(0)
while True:
r, w, e = select.select([sslsock], [], [])
if sslsock in r:
try:
data = sslsock.recv(1024)
except ssl.SSLError as e:
# Ignore the SSL equivalent of EWOULDBLOCK, but re-raise other errors
if e.errno != ssl.SSL_ERROR_WANT_READ:
raise
continue
# No data means end of file
if not data:
break
# Drain the SSL socket's internal buffer.
# If you want to remove the loop, make sure you don't call recv()
# with a 0 length, since that could cause a read to the raw socket.
data_left = sslsock.pending()
while data_left:
data += sslsock.recv(data_left)
data_left = sslsock.pending()
# Process the data
process(data)
如果您发布一个代码示例(简化为其基本核心),这会有所帮助。Python2.6
ssl
模块的文档表明,将wrap_socket()返回的套接字传递给select()应该可以工作。是的,我确实让它工作起来了,我不太确定我做错了什么,但我猜是有问题的。谢谢你的回答。
# Put the SSL socket to non-blocking mode
sslsock.setblocking(0)
while True:
r, w, e = select.select([sslsock], [], [])
if sslsock in r:
try:
data = sslsock.recv(1024)
except ssl.SSLError as e:
# Ignore the SSL equivalent of EWOULDBLOCK, but re-raise other errors
if e.errno != ssl.SSL_ERROR_WANT_READ:
raise
continue
# No data means end of file
if not data:
break
# Drain the SSL socket's internal buffer.
# If you want to remove the loop, make sure you don't call recv()
# with a 0 length, since that could cause a read to the raw socket.
data_left = sslsock.pending()
while data_left:
data += sslsock.recv(data_left)
data_left = sslsock.pending()
# Process the data
process(data)