【发布时间】:2018-03-22 04:15:18
【问题描述】:
我正在使用 pycharm 运行 Windows 10、python 2.7 我正在做一个套接字聊天室的练习,我偶然发现了一个问题:
从多个 cmd 窗口运行客户端和服务器套接字时, 当我突然退出一个 cmd 窗口时,服务器应该向剩余的客户端转发一条消息 - 通知他们一个客户端离开了(包括客户端的昵称)
由于某种原因,这被证明是一个问题,服务器似乎将该客户端保留在客户端列表中,引发错误,好像我向他发送了该消息(这显然是有问题的,因为他不再在那里)。
当我试图解决这个问题时——将循环更改为不向特定客户端发送消息(通过保存他的套接字对象)——它不会发送任何消息。 好像它不识别其他客户端一样。
我的代码:
服务器:
import socket
import select
import datetime
server_socket=socket.socket()
server_socket.bind(('127.0.0.1',23))
server_socket.listen(5)
open_client_sockets = []
messages_to_send = []
chat_clients={}
def send_waiting_messages(wlist):
for message in messages_to_send:
(sender,msg)=message
if(msg=='\r'):
continue
elif(msg=='quit'):
pass
else:
nick_len=int(msg[:2])
nick=msg[2:2+nick_len]
chat=msg[2+nick_len:]
chat_clients[sender]=nick
for client in wlist:
if(msg=='quit'):
client.send(('{:02d}:{:02d} {} has left the chat!'.format(datetime.datetime.now().hour,datetime.datetime.now().minute,sender)))
else:
if(client is sender):
client.send('NL')
else:
client.send('{:02d}:{:02d} {}: {}'.format(datetime.datetime.now().hour,datetime.datetime.now().minute,nick,chat))
messages_to_send.remove(message)
while True:
rlist,wlist,xlist=select.select([server_socket] + open_client_sockets,open_client_sockets,[])
for current_socket in rlist:
print wlist
if(current_socket is server_socket):
(new_socket,address)=server_socket.accept()
open_client_sockets.append(new_socket)
chat_clients[new_socket]=''
else:
try:
msg=current_socket.recv(1024)
except socket.error as e:
if e.errno==10054:
msg=''
else:
raise
if(msg=='' or msg=='quit'):
if(msg=='quit'):
messages_to_send.append((chat_clients[current_socket], 'quit'))
current_socket.send('quit')
open_client_sockets.remove(current_socket)
del chat_clients[current_socket]
else:
print '{:02d}:{:02d} {} has left the chat!'.format(datetime.datetime.now().hour,
datetime.datetime.now().minute, chat_clients[current_socket])
messages_to_send.append((current_socket, 'quit'))
else:
print msg
messages_to_send.append((current_socket,msg))
send_waiting_messages(wlist)
客户:
import socket
import select
import datetime
server_socket=socket.socket()
server_socket.bind(('127.0.0.1',23))
server_socket.listen(5)
open_client_sockets = []
messages_to_send = []
chat_clients={}
def send_waiting_messages(wlist):
for message in messages_to_send:
(sender,msg)=message
if(msg=='\r'):
continue
elif(msg=='quit'):
pass
else:
nick_len=int(msg[:2])
nick=msg[2:2+nick_len]
chat=msg[2+nick_len:]
chat_clients[sender]=nick
for client in wlist:
if(msg=='quit'):
client.send(('{:02d}:{:02d} {} has left the chat!'.format(datetime.datetime.now().hour,datetime.datetime.now().minute,sender)))
else:
if(client is sender):
client.send('NL')
else:
client.send('{:02d}:{:02d} {}: {}'.format(datetime.datetime.now().hour,datetime.datetime.now().minute,nick,chat))
messages_to_send.remove(message)
while True:
rlist,wlist,xlist=select.select([server_socket] + open_client_sockets,open_client_sockets,[])
for current_socket in rlist:
print wlist
if(current_socket is server_socket):
(new_socket,address)=server_socket.accept()
open_client_sockets.append(new_socket)
chat_clients[new_socket]=''
else:
try:
msg=current_socket.recv(1024)
except socket.error as e:
if e.errno==10054:
msg=''
else:
raise
if(msg=='' or msg=='quit'):
if(msg=='quit'):
messages_to_send.append((chat_clients[current_socket], 'quit'))
current_socket.send('quit')
open_client_sockets.remove(current_socket)
del chat_clients[current_socket]
else:
print '{:02d}:{:02d} {} has left the chat!'.format(datetime.datetime.now().hour,
datetime.datetime.now().minute, chat_clients[current_socket])
messages_to_send.append((current_socket, 'quit'))
else:
print msg
messages_to_send.append((current_socket,msg))
send_waiting_messages(wlist)
我们将不胜感激!
【问题讨论】:
-
如果客户端在消息发送之前就退出了,那么服务器显然永远不会收到退出消息。我会将广播代码包装在 try...catch 中。如果向客户端发送消息会产生套接字错误,则表明它们已断开连接。
-
@Carcigenicate 我试过用它,把上面的代码改成: if(msg=='quit'): try: client.send(('{:02d}:{:02d} {}已离开聊天!'.format(datetime.datetime.now().hour,datetime.datetime.now().minute,sender))) except: continue 应该跳过有问题的客户端并将其发送给相关那些。但是它只循环和打印 wlist。 - 服务器的 while 循环中的第 4 行。