目前我正在开发一个聊天服务器/客户端项目。 我正在努力处理使用select的多个请求,我的服务器脚本使用select模块但客户端脚本没有。结果是,当用户输入消息时,其他客户端必须编写自己的消息以通读对话。我在网上搜索了很多例子,但是只能找到sys.stdin的代码片段,这不是我想要的。
我很乐意接受任何指示/解释。
服务器代码:
import socket
import select
server_socket = socket.socket()
server_socket.bind(("0.0.0.0", 2855))
server_socket.listen(1)
open_client_sockets = [] # current clients handler
messages_to_send = [] # future message send handler
def send_waiting_messages(wlist):
for message in messages_to_send:
(client_socket, data) = message
if client_socket in wlist: # if current socket in iteration has reading abilities
client_socket.send(data)
messages_to_send.remove(message) # remove from future send handler
def broadcast_message(sock, message):
for socket in open_client_sockets:
if socket != server_socket and socket != sock:
socket.send(message)
while True:
rlist, wlist, xlist = select.select([server_socket] + open_client_sockets, open_client_sockets, []) # apending reading n writing socket to list
for current_socket in rlist: # sockets that can be read
if current_socket is server_socket: # if there is a new client
(new_socket, address) = server_socket.accept()
open_client_sockets.append(new_socket) # clients list
else:
data = current_socket.recv(1024)
if len(data) == 0:
open_client_sockets.remove(current_socket) # remove user if he quit.
print "Connection with client closed."
send_waiting_messages(wlist) # send message to specfic client
else:
broadcast_message(current_socket, "\r" + '<' + data + '> ')
# send_waiting_messages(wlist) # send message to specfic client
server_socket.close()
客户代码:
import socket
import msvcrt
client_socket = socket.socket()
client_socket.connect(("127.0.0.1", 2855))
data = ""
def read_message():
msg = ""
while True:
if msvcrt.kbhit():
key = msvcrt.getch()
if key == '\r': # Enter key
break
else:
msg = msg + "" + key
return msg
while data != "quit":
data = read_message()
client_socket.send(data)
data = client_socket.recv(1024)
print data
client_socket.close()
答案 0 :(得分:2)
我的服务器脚本使用select模块,但客户端脚本没有。
解决方案是在客户端也使用select
。在Windows上,遗憾的是select
无法处理sys.stdin
,但我们可以使用 timeout 参数来轮询键盘。
import socket
import select
import msvcrt
client_socket = socket.socket()
client_socket.connect(("localhost", 2855))
msg = ""
while True:
ready = select.select([client_socket], [], [], .1)
if client_socket in ready[0]:
data = client_socket.recv(1024)
print data, ' '*(len(msg)-len(data))
print msg,
if msvcrt.kbhit():
key = msvcrt.getche()
if key == '\r': # Enter key
if msg == "quit":
break
client_socket.send(msg)
msg = ""
print
else:
msg = msg + "" + key
client_socket.close()
答案 1 :(得分:0)
服务器端和客户端都存在阻止应用程序真正实时的问题。以下是我迄今为止注意到的几个问题:
只有在将一些数据写入套接字后,客户端才会从服务器连接读取数据。考虑将从套接字读取的逻辑放入单独的线程中。
在您的服务器中,您在向客户端发送待处理消息之前,对rlist
返回的select()
进行迭代;如果客户端已发送消息,则客户端fds将仅出现在rlist中。发送消息应该基于可写的fds,通过遍历wlist来完成。但这有其他问题......
您对所有客户端fds的可写性始终select()
,即使没有待处理的消息要写入该客户端。最终的结果是你的select()
调用几乎总会立即返回,并且会浪费CPU(这种选择的目的会失败)
所有套接字IO都在&#34;阻塞&#34;模式,因此如果您发送的内核接收缓冲区可以处理的更多数据(通常大约10MB),您的send()
可能会阻塞。
使用异步框架(例如twisted)来实现这种类型的应用程序会好得多。管理所有缓冲区可能既繁琐又具有挑战性,而且之前的工作已经完成。