Python socket non-blocking with SSL 的问题
2018-01-02 16:35
302 查看
最近要直接用Socket做一个简单的Server,想使用non-blocking的Scoket,但是遇到一些问题,解决了所以在这里总结一下。
简单的Server端代码片段(只有接受数据的):
由于
在成功握手后,发现一个问题,调用
如果读取范围较大,会出现
这个错误,表示读未完成。
而使用
发现使用
,直至错误出现。
而直接使用
更深入的原因还没找出,目前觉得应该是makefile后把socket当成文件读取,会尝试读直至无法继续读取,所以才会导致错误发生。
简单的Server端代码片段(只有接受数据的):
#!/usr/bin/env python # -*- coding: UTF-8 -*- import ssl import select import socket DEFAULT_SERVER_HOST = "0.0.0.0" DEFAULT_SERVER_PORT = 14443 class Server(object): def __init__(self, host, port, is_ssl=False, cert_file=None, key_file=None): self.host = host self.port = port self.is_ssl = is_ssl self.cert_file = cert_file self.key_file = key_file self.context = None self.__socket = None self.running = False self.multiplex = None self.read_set = set() self.write_set = set() self.error_set = set() def __initialize(self): if self.is_ssl and (self.cert_file is None or self.key_file is None): raise Exception("If you want to enable ssl, please set cert_file and key_file") if self.is_ssl: self.context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) self.context.load_cert_chain(certfile=self.cert_file, keyfile=self.key_file) self.__socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.__socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT & socket.SO_REUSEADDR, 1) self.__socket.bind((self.host if self.host is not None else DEFAULT_SERVER_HOST, self.port if self.port is not None else DEFAULT_SERVER_PORT)) self.__socket.setblocking(0) self.__socket.listen(5) def start(self): self.__initialize() server_fd = self.__socket.fileno() self.read_set.add(server_fd) while True: read_list, write_list, error_list = select.select(self.read_set, self.write_set, self.error_set, 2) if server_fd in read_list: conn, addr = self.__socket.accept() conn.setblocking(0) if self.is_ssl: conn = self.context.wrap_socket(conn, server_side=True, do_handshake_on_connect=False) i = 0 while True: i += 1 print(i) try: conn.do_handshake() select.select([conn], [], []) break except ssl.SSLError as err: if err.args[0] == ssl.SSL_ERROR_WANT_READ: print("read") select.select([conn], [], []) elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: print("write") select.select([], [conn], []) else: raise # rfile = conn.makefile("rb") # a = rfile.read(1024*8) a = conn.recv(1024*8) print(a) if __name__ == "__main__": cs = Server("0.0.0.0", 14443, True, "snakeoil.crt", "snakeoil.key") cs.start()
由于
self.__socket.setblocking(0)
conn.setblocking(0)都设置为非阻塞,所以
conn = self.context.wrap_socket(conn, server_side=True, do_handshake_on_connect=False)不能设置为连接时自动握手。
在成功握手后,发现一个问题,调用
rfile = conn.makefile("rb") a = rfile.read(1024*8)
如果读取范围较大,会出现
Traceback (most recent call last): File "/home/ming/Application/pycharm-2017.1.4/helpers/pydev/pydevd.py", line 1591, in <module> globals = debugger.run(setup['file'], None, None, is_module) File "/home/ming/Application/pycharm-2017.1.4/helpers/pydev/pydevd.py", line 1018, in run pydev_imports.execfile(file, globals, locals) # execute the script File "/home/ming/Application/pycharm-2017.1.4/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile exec(compile(contents+"\n", file, 'exec'), glob, loc) File "/home/ming/PycharmProjects/Test/server.py", line 86, in <module> cs.start() File "/home/ming/PycharmProjects/Test/server.py", line 80, in start a = rfile.read(1024*8) File "/home/ming/.pyenv/versions/3.5.3/lib/python3.5/socket.py", line 576, in readinto return self._sock.recv_into(b) File "/home/ming/.pyenv/versions/3.5.3/lib/python3.5/ssl.py", line 937, in recv_into return self.read(nbytes, buffer) File "/home/ming/.pyenv/versions/3.5.3/lib/python3.5/ssl.py", line 799, in read return self._sslobj.read(len, buffer) File "/home/ming/.pyenv/versions/3.5.3/lib/python3.5/ssl.py", line 583, in read v = self._sslobj.read(len, buffer) ssl.SSLWantReadError: The operation did not complete (read) (_ssl.c:2090)
这个错误,表示读未完成。
而使用
a = conn.recv(1024*8)则不会发生错误。
发现使用
makefile()后的读操作,将会多次调用
ssl.py的
SSLSocket.class的
recv_into方法,最后到
ssl.py的
SSLObject
def read(self, len=1024, buffer=None): """Read up to 'len' bytes from the SSL object and return them. If 'buffer' is provided, read into this buffer and return the number of bytes read. """ if buffer is not None: v = self._sslobj.read(len, buffer) //makefile 后执行这句 else: v = self._sslobj.read(len) return v
,直至错误出现。
而直接使用
socket的
read方法,则是直接调用
ssl.py的
SSLObject的
def read(self, len=1024, buffer=None): """Read up to 'len' bytes from the SSL object and return them. If 'buffer' is provided, read into this buffer and return the number of bytes read. """ if buffer is not None: v = self._sslobj.read(len, buffer) else: v = self._sslobj.read(len) // socket 的read执行这句 return v
更深入的原因还没找出,目前觉得应该是makefile后把socket当成文件读取,会尝试读直至无法继续读取,所以才会导致错误发生。
相关文章推荐
- compiling-python-with-ssl-support问题
- 解决Python代码编码问题 SyntaxError: Non-UTF-8 code starting with '\xc1'
- 解决Python代码编码问题 SyntaxError: Non-UTF-8 code starting with '\xc1'
- Python代码编码问题:SyntaxError: Non-UTF-8 code starting with '\xe4'
- Python: 使用select函数编写nonblocking TCP/IP socket程序
- epoll ET mode with tcp nonblocking socket
- SyntaxError: Non-ASCII character ‘\xe5′ in file 关于python中的编码问题
- TLS,SSL,HTTPS with Python
- python socket ssl编程
- [编码问题] Python错误: SyntaxError: Non-ASCII character
- Python 下socket编程地址被占用问题:Address already in use
- python socket编程---从使用Python开发一个Socket示例说到开发者的思维和习惯问题
- Verilog非阻塞赋值的仿真/综合问题(Nonblocking Assignments in Verilog Synthesis) -下-
- python3安装文件遇到ssl未安装问题
- Fast portable non-blocking network programming with Libevent
- Python中Socket的Close方法假关闭Socket连接的问题
- mutual certificate authentication(双向认证实例)ssl with Python
- 关于python中with 和 try 块的联合使用的问题
- 解决qt5上qt.network.ssl: QSslSocket: cannot call unresolved function TLSv1_1_client_method 问题
- 从使用Python开发一个Socket示例说到开发者的思维和习惯问题