python 中的 select 和 ssl
我有一个使用 select.select() 的服务器应用程序,现在我尝试向其中添加 SSL,但是在侦听“原始”套接字时出现以下错误:
ValueError: file descriptor cannot be a negative integer (-1)
所以我想我应该使用 ssl而是由 ssl.wrap_socket 在 select 中返回的流。这样做,它不会返回任何错误,但也不起作用 - 我不太确定问题是什么,我做了很多研究并遇到了类似问题的帖子,但我发现没有解决这个问题还没有。
非常感谢任何帮助。
I've got a server application using select.select(), and now I'm trying to add SSL to it, however I get the following error when listening to the "raw" sockets:
ValueError: file descriptor cannot be a negative integer (-1)
so I figured I'd use the ssl streams returned by ssl.wrap_socket in select instead. Doing so, it doesn't return any errors but it doesn't work either - I'm not really sure what the problem is, I've done a lot of research and encountered posts with similar problems, but I've found no solution to this yet.
Really appreciate any help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
将 SSL 套接字与
select()
一起使用并不像乍看起来那么简单。虽然它们工作得很好,因为当你给它一个错误时它不会抛出错误,但如果你只是像普通套接字一样使用它们,你迟早会遇到一些奇怪的情况。由于 select() 需要文件描述符,因此它将获取原始套接字。但即使原始套接字变得可读,也不意味着您将从 SSL 套接字获取数据。您需要使用非阻塞套接字(无论如何,在使用
select()
时这是一个好主意),并且如果它抛出SSL_ERROR_WANT_READ
(SSL 相当于EWOULDBLOCK
)。另一个问题是,如果您向另一端的连接写入 2048 字节,则您一端的
select()
返回。但是,如果您只从 SSL 套接字读取 1024 字节,则 SSL 套接字内部可能会读取更多数据,并且下一个select()
将不会返回,即使会有更多数据要读取。读取,可能会导致连接死锁。这是因为select()
使用的原始套接字没有任何数据,因为它已经在 SSL 套接字的缓冲区中。我想到的第一个解决方案是读取更多数据,直到读取抛出 SSL_ERROR_WANT_READ ,从而清空缓冲区。但是,如果另一端生成数据的速度比您处理数据的速度快,则最终会导致所有其他连接处于饥饿状态,直到这一端完成数据生成。
您可以通过调用 sslsock.pending() 来查看 SSL 套接字持有多少缓冲数据。那么,更好的方法是首先对一定数量的数据进行一次读取,检查待处理的数据量,然后针对该数量的数据发出第二次读取,从而清空缓冲区,而不会导致更多的读取。
SSL_pending()
(幕后的 C 函数)的手册页也这样说:根据我的理解,这意味着如果设置了 read_ahead,您需要重复第二步,直到 SSL_pending() 返回 0。我很确定 python 没有设置 read_ahead,但安全总比后悔好,所以我在示例代码中包含了循环。
我对此不太熟悉,但这样的事情应该有效:
Using SSL sockets with
select()
isn't as straightforward as it may seem at first. While they work okay with it in the sense that it doesn't throw an error when you give it one, if you just use them like normal sockets, you're bound to bump into some weirdness sooner or later.Since
select()
needs a file descriptor, it's going to get the raw socket. But even if the raw socket becomes readable, that doesn't mean you will get data out of the SSL socket. You'll need to use non-blocking sockets (which is a good idea anyway when usingselect()
) and just ignore it if it throwsSSL_ERROR_WANT_READ
(the SSL equivalent ofEWOULDBLOCK
).Another problem is, if you write 2048 bytes to the connection at the other end, the
select()
on your end returns. But if you then only read 1024 bytes from the SSL socket, it is possible that the SSL socket internally reads more data, and the nextselect()
won't return even though there would be more data to read, possibly deadlocking the connection. This is because the raw socket, which is whatselect()
is using, doesn't have any data since it's already in the SSL socket's buffers.The first solution that comes to mind would be to read more data until reading throws
SSL_ERROR_WANT_READ
, thus emptying the buffer. However, if the other end generates data faster than you can process it, this would end up starving all your other connections until this one finishes generating data.You can see how much buffered data the SSL socket is holding by calling
sslsock.pending()
. A better approach, then, would be to first do one read for some amount of data, check the amount of pending data and issue a second read for exactly that amount of data, thus emptying the buffer without causing any more reads.The man-page for
SSL_pending()
(the C function behind the scenes) also says this:From what I understand, this means that if
read_ahead
is set, you'd need to repeat the second step untilSSL_pending()
returns 0. I'm pretty sure python doesn't setread_ahead
, but it's better be safe than sorry, so I've included the loop in the example code.I'm not that familiar with this, but something like this should work:
正如 Marius 指出的那样, select.select() 适用于 SSL 套接字,我仍然不知道是什么导致了我的无声错误,但当我认为它是 SSL + select() 时,我就急了。这样这个问题就得到了解答。
As Marius pointed out, select.select() works with SSL sockets, I still do not know what caused my silent error but I jumped my gun when thinking it was SSL + select(). Thus this question is answered.