python - sel.unregister(clt_socket) 不从选择器中删除套接字
问题描述
这里是社区的新手,尝试学习 Python 作为职业支点的一部分。
尝试使用选择器创建基本的多客户端套接字服务器。在客户提交关闭聊天的请求之前,一切似乎都很好。此时服务器调用sel.unregister(clt_socket)
然后关闭服务器端的clt_socket,一切都没有错误。但是,关联的密钥保持注册状态,因此sel.select()
仍会尝试将其传递给service_client()
方法,这会导致 OSError。
尽管我头疼了几个小时,尽管阅读了 python 文档、谷歌搜索、stackoverflow 搜索,但我无法弄清楚我做错了什么。
您能提供的任何帮助将不胜感激。
谢谢!
错误:
Failed while working with key: SelectorKey(fileobj=<socket.socket [closed] fd=-1, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0>, fd=64, events=3, data=namespace(clt_address=('127.0.0.1', 50377), inc_msg=b'q', out_msg=b''))
服务器:
from socket import *
import selectors
import types
def accept_client(srv_socket):
# accept new client if selector finds srv_socket gets a NIL data connection
clt_socket, clt_address = srv_socket.accept()
print ('New client connected: '+str(clt_address))
clt_socket.setblocking(False)
# create a place to put our data
data = types.SimpleNamespace(clt_address=clt_address,inc_msg=b'',out_msg=b'')
# registors socket in selector for both reading and writing
events = selectors.EVENT_READ | selectors.EVENT_WRITE
sel.register(clt_socket,events,data=data)
# process ready events (mask) for clt_socket(key.data)
def service_client(key,mask):
clt_socket = key.fileobj
# socket ready to read when both are True
if mask & selectors.EVENT_READ:
key.data.inc_msg = key.fileobj.recv(1024)
print (str(key.data.clt_address)+' said: '+key.data.inc_msg.decode('utf-8'))
if key.data.inc_msg == 'q'.encode('utf-8'):
sel.unregister(key.fileobj)
key.fileobj.close()
print ('Chat closed BY: '+str(key.data.clt_address))
else:
key.data.out_msg = input('Reply to '+str(key.data.clt_address)+' :').encode('utf-8')
# sockets should always be ready for write
if mask & selectors.EVENT_WRITE:
sent = key.fileobj.send(key.data.out_msg)
key.data.out_msg = key.data.out_msg[sent:]
if key.data.out_msg == 'q'.encode('utf-8'):
sel.unregister(key.fileobj)
key.fileobj.close()
print ('Chat closed FOR : '+str(key.data.clt_address))
# define server parameters (using localhost IPv4 address)
print ('Defining server parameters...')
srv_ip = '127.0.0.1'
srv_port = 6789
srv_address = (srv_ip,srv_port)
# create & bind TCP srv_socket, with NON-BLOCKING listen for connections
print ('Starting server. Listening for connections...')
srv_socket = socket(AF_INET,SOCK_STREAM)
srv_socket.bind((srv_address))
srv_socket.listen() # default queue 5
srv_socket.setblocking(False)
# register srv_socket with selector to monitor for read evts (clt connections?)
sel = selectors.DefaultSelector()
sel.register (srv_socket,selectors.EVENT_READ,data=None)
# create event loop
while True:
events = sel.select(timeout = None) # get (key,evts) per reg socket
for key, mask in events:
try:
if key.data is None: # no data = new clt (from listen)
accept_client(key.fileobj)# accept it! (key.fileobj = srv_socket)
else: # yes data = old clt
service_client(key,mask) # service it!
except:
print('Failed while working with key: ',str(key))
continue
# NOT being called at the moment
srv_socket.close()
print ('Exiting program')```
客户:
from datetime import datetime
HOST = '127.0.0.1'
PORT = 6789
max_size = 1024
print ('Starting the client at : ',datetime.now())
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((HOST,PORT))
print ('Connection established with server.')
print ('Initating protocols to send and receive messages...')
while True:
message_to_send = input('Enter msg: ').encode('utf-8')
s.sendall(message_to_send)
if message_to_send == 'q'.encode('utf-8'):
break
received_message = s.recv(max_size).decode('utf-8')
print('Server said: ',received_message)
if received_message == 'q':
break
print ('Closing connection...')
s.close()```
解决方案
我return
编辑了选择器,这似乎起到了作用。
不确定这是否是正确的方法,但它确实有效。
推荐阅读
- c# - 无法从 appsettings 获取对象列表
- python - 在 Python 的子进程命令行中使用 osmtogeosjon 将 OSM 文件转换为 geojson 文件
- jenkins - Jenkins 中缺少管道选项卡
- node.js - MongoDB/Mongoose 断开连接时出现未处理错误 - 为什么它不触发 ('error') 事件?
- vue.js - 对象上的 Vuex 状态更改不会触发重新渲染
- python - 无法将数据框列的数据类型更改为 int
- google-colaboratory - Google colab 错误 - 笔记本加载错误:
- sql - SQL:在选择中使用 Lag/Lead 结果两次
- scala - slick 可以从模型中自动在数据库中创建表(生成 SQL 并执行)吗?
- c# - UDPClient收到多条消息后失去连接