首页 > 解决方案 > 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()```

标签: pythonsocketskeychatselector

解决方案


return编辑了选择器,这似乎起到了作用。

不确定这是否是正确的方法,但它确实有效。


推荐阅读