在SSL套接字上使用部分recv()的python的select()行为

Rob*_*bNY 4 python sockets ssl network-programming

我创建了一个SSL套接字(服务器端)并将套接字放入select()队列.当套接字"准备好"读取时,select()正确返回.

然后我recv(1024)字节.在某些情况下,这将获得所有数据,而在其他情况下,它可能不会.

但是,如果套接字缓冲区中仍有数据(因为我没有全部recv()),并且我再次将同一个套接字传递给select(),它将不会被返回为"准备好"进行读取,即使我知道那里有数据.

我想我的问题是确实从select()的角度来确认"准备阅读"的真正意义,以及处理这个问题的最佳方法是什么.继续recv()直到EWOULDBLOCK看起来有点黑客 - 因为我正在使用select().

我错误地想到了这个吗?我意识到我可以使用更大的recv缓冲区,但总有可能会有更多的读取而不是recv可以拉 - 所以什么是"正确"的方式来处理这个来自select()?

提前致谢.

编辑:如评论中所述,我忽略了提到这是一个SSL服务器,显然select()在使用包裹套接字时表现不同.

Ste*_*ich 6

select从操作系统内核的角度来看,只关心套接字的准备情况.那就是检查套接字是否准备就绪,recv只选择检查套接字缓冲区中是否有数据.但是由于涉及用户空间缓冲,因此使用SSL会有所不同.

即使您只读取SSL套接字中的几个字节,它也需要读取包含加密数据的完整SSL记录,解密完整记录,然后它可以返回您请求的几个字节.其余数据将缓存在用户空间中以供下次读取.但是,从OS套接字缓冲区中删除了完整的SSL记录,这意味着select可能无法显示仍有可用的数据.

有两种方法可以解决这个问题.一种方法是使用pending方法来查找在用户空间中缓存的数据.另一种是始终recv处于巨大的块中,以便不会在用户空间中缓冲数据.由于SSL记录的最大大小为16k,并且每个recv只处理一个SSL记录(openssl SSL_read中的实现细节),因此始终调用recv大小至少为16384.