我有一个用Python编写的小服务器/客户端脚本。
server.py创建一个新套接字并生成两个子节点。 在子进程中我为EPOLLIN事件注册了socket des criptor,所以 我可以在孩子的套接字上做一个接受。问题是,两个孩子都是 根据客户要求通知,但只有一个孩子接受,另一个接受 抛出异常“[Errno 11]资源暂时不可用”。 如果他们无法在套接字上接受通知,我如何阻止所有儿童收到通知?
--- --- server.py
import socket, time, os, select
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('127.0.0.1', 10000))
sock.listen(256)
sock.setblocking(False)
for _ in range(0,2):
pid = os.fork()
if pid == 0: #in child
poll = select.epoll()
poll.register(sock.fileno(), select.EPOLLIN)
while True:
events = poll.poll(2) # listening for events with 2 sec timeout
for fileno, event in events:
if event & select.EPOLLIN: # there is data on socket available
print("EPOLLIN in PID: " + str(os.getpid()))
try:
clientsock, addr = sock.accept()
clientsock.close()
print("accepted and closed in PID: " + str(os.getpid()))
except Exception as e:
print("PID: " + str(os.getpid()) + " " + str(e))
# we are in parent process, keep it live
while True:
time.sleep(10)
客户端仅向服务器发出一个请求:
--- --- client.py
import socket, time, select, sys
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost',10000))
s.setblocking(False)
s.close()
执行“client.py”后,我从服务器获得以下输出:
EPOLLIN in PID: 9424
EPOLLIN in PID: 9425
PID: 9424 [Errno 11] Resource temporarily unavailable
accepted and closed in PID: 9425
正如你所看到的,他们两个都得到了一个EPOLLIN,但只有一个得到了实际的接受,另一个得到了 抛出异常。
答案 0 :(得分:0)
“资源暂时不可用”是EAGAIN,在这种情况下,这意味着您目前无法accept()
,这是自然的,因为其他进程已经accept()
。 EAGAIN不是致命错误,在这种情况下可以忽略。或者,您可以在主进程中处理accept()
,并使用队列来处理连接到工作进程的套接字。
对于实际使用(与实验和学习相反),我热烈建议使用生产框架,如Twisted。
答案 1 :(得分:0)
它按设计工作:如果所有孩子都能接受新客户并且他们都会得到通知,您希望所有孩子都收到通知。目前epoll返回两者都可以调用accept。但是如果只有一个客户端连接,那么accept只能返回一次成功。如果多个客户端正在连接,那么另一个接受也会成功。
所以你真正想要的是只有当客户端当前在监听队列中时才会被唤醒。不幸的是,没有办法用系统定义的API做这样的事情(这不是python的问题)。因此,通常的方法是忽略EAGAIN并等待下一个客户端。