[英]BlockingIOError: [Errno 35] Resource temporarily unavailable For Loop
[英]Socket Error in Python: BlockingIOError: [Errno 35] Resource temporarily unavailable
所以这里有问题。 我尝试在Python中使用socket实现一个简单的 Web 服务器。 单线程版本运行良好。 但是当我尝试使用非阻塞模式实现更多线程时,它会出现错误。我尝试在 Stackoverflow 和 Google 中搜索,但没有答案。 这是我的代码:
# coding:utf-8
import errno
import socket
import threading
import time
EOL1 = b'\n\n'
EOL2 = b'\n\r\n'
body = '''<h1>Hello, world!</h1> - from {thread_name}'''
response_params = [
'HTTP/1.0 200 OK',
'Date: Mon, 01 jan 2022 01:01:01 GMT'
'Content-Type: text/plain; charset=utf-8',
'Content_Length: {length}\r\n',
body,
]
response = '\r\n'.join(response_params)
def handle_connection(conn, addr):
# print(conn, addr)
# time.sleep(60)
request = b""
while EOL1 and EOL2 not in request:
request += conn.recv(1024) # ERROR HERE!
print(request)
current_thread = threading.currentThread()
content_length = len(body.format(thread_name=current_thread.name).encode())
print(current_thread.name)
conn.send(response.format(thread_name=current_thread.name,
length = content_length).encode())
conn.close()
def main():
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversocket.bind(('127.0.0.1', 8000))
serversocket.listen(10)
print('http://127.0.0.1:8000')
serversocket.setblocking(0)
try:
i = 0
while True:
try:
conn, address = serversocket.accept()
except socket.error as e:
if e.args[0] != errno.EAGAIN:
raise
continue
i += 1
print(i)
t = threading.Thread(target=handle_connection, args=(conn, address),
name = 'thread-%s' % i)
t.start()
finally:
serversocket.close()
if __name__ == '__main__':
main()
错误消息在这里:
1
Exception in thread thread-1:
2
Traceback (most recent call last):
File "/Users/tdeveloper/opt/anaconda3/lib/python3.9/threading.py", line 973, in _bootstrap_inner
Exception in thread thread-2:
Traceback (most recent call last):
File "/Users/tdeveloper/opt/anaconda3/lib/python3.9/threading.py", line 973, in _bootstrap_inner
self.run()
self.run()
File "/Users/tdeveloper/opt/anaconda3/lib/python3.9/threading.py", line 910, in run
File "/Users/tdeveloper/opt/anaconda3/lib/python3.9/threading.py", line 910, in run
self._target(*self._args, **self._kwargs)
File "/Users/tdeveloper/Development/Learning/Python_Simple_WSGI/socket/thread_socketserver.py", line 26, in handle_connection
self._target(*self._args, **self._kwargs)
File "/Users/tdeveloper/Development/Learning/Python_Simple_WSGI/socket/thread_socketserver.py", line 26, in handle_connection
request += conn.recv(1024)
BlockingIOError: [Errno 35] Resource temporarily unavailable
request += conn.recv(1024)
BlockingIOError: [Errno 35] Resource temporarily unavailable
请帮我。 非常感谢。
这显然是关于非阻塞标志的 inheritance 的accept
的 macOS 实现不同于其他平台的问题。 它与线程本身无关。
这是一个演示的精简单线程测试程序。
#!/usr/bin/env python3
import select
import socket
ssocket = socket.socket()
ssocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
ssocket.bind(('127.0.0.1', 7000))
ssocket.listen(10)
ssocket.setblocking(0) # <<<<<<<===========
select.select([ssocket], [], [])
csocket, caddr = ssocket.accept()
csocket.recv(10)
如果您在 linux 上运行它,并使用nc localhost 7000
连接到它, csocket.recv
会按您的预期阻塞。 在 macos 上运行相同的程序, recv
会立即触发您看到的BlockingIOException
。
查看 macos 上的手册页accept(2)
显示:
[...] 创建一个具有与套接字相同属性的新套接字
在这种情况下,非阻塞文件描述符标志( O_NONBLOCK
)被新套接字“继承”。 因此,如果您不想要它,则需要使用conn.setblocking(1)
在接受的套接字上禁用它。 显然,这种行为是由于 MacOS 源自 Unix 的 BSD 风格。
综上所述,您无需禁用阻塞,除非您的实际程序比显示的更多。 即,如果您的主线程除了接受连接之外什么都不做,然后分离一个单独的线程来处理连接,那么没有理由不让主线程阻塞在accept
中。 如果您允许侦听套接字保持阻塞模式,则接受的 sockets 也应该处于阻塞模式。 (顺便说一句,你在那个主线程循环中浪费了大量的 CPU 时间:调用accept
,捕获异常,然后continue
重新开始循环。)
(For clarity, my specs: python 3.7.3 downloaded from https://www.python.org/ftp/python/3.7.3/python-3.7.3-macosx10.9.pkg running on MacOS Catalina 10.15.7)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.