使用select处理多个请求

时间:2014-12-19 19:02:39

标签: python sockets select

目前我正在开发一个聊天服务器/客户端项目。 我正在努力处理使用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()

2 个答案:

答案 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)

服务器端和客户端都存在阻止应用程序真正实时的问题。以下是我迄今为止注意到的几个问题:

  1. 只有在将一些数据写入套接字后,客户端才会从服务器连接读取数据。考虑将从套接字读取的逻辑放入单独的线程中。

  2. 在您的服务器中,您在向客户端发送待处理消息之前,对rlist返回的select()进行迭代;如果客户端已发送消息,则客户端fds将仅出现在rlist中。发送消息应该基于可写的fds,通过遍历wlist来完成。但这有其他问题......

  3. 您对所有客户端fds的可写性始终select(),即使没有待处理的消息要写入该客户端。最终的结果是你的select()调用几乎总会立即返回,并且会浪费CPU(这种选择的目的会失败)

  4. 所有套接字IO都在&#34;阻塞&#34;模式,因此如果您发送的内核接收缓冲区可以处理的更多数据(通常大约10MB),您的send()可能会阻塞。

  5. 使用异步框架(例如twisted)来实现这种类型的应用程序会好得多。管理所有缓冲区可能既繁琐又具有挑战性,而且之前的工作已经完成。