【问题标题】:Handle multiple requests with select使用 select 处理多个请求
【发布时间】:2015-02-18 18:15:21
【问题描述】:

目前我正在开发一个聊天服务器/客户端项目。 我正在努力使用 select 处理多个请求,我的服务器脚本使用 select 模块,但客户端脚本没有。结果是,当用户输入消息时,其他客户端必须编写自己的消息才能阅读对话。我在网上搜索了很多示例,但只能找到带有 sys.stdin 的代码 sn-ps,这不是我想要的。

我很乐意收到任何指示/解释。

服务器代码:

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()

【问题讨论】:

  • 这比看起来要难得多。我可以建议你看看扭曲吗? twistedmatrix.com/trac
  • 不,我知道扭曲,但我想自己实现它。谢谢你!
  • 你的客户为什么要手动实现raw_input()
  • 因为 raw_input() 是一个阻塞函数。

标签: python sockets select


【解决方案1】:

我的服务器脚本使用了选择模块,但客户端脚本没有。

一种解决方案是在客户端中也使用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()

【讨论】:

    【解决方案2】:

    服务器端和客户端都存在一些问题,这些问题会阻止您的应用程序真正实现实时性。以下是我目前注意到的几个:

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

    2. 在您的服务器中,您遍历select() 返回的rlist,然后将待处理的消息发送到客户端;如果客户端发送了一条消息,客户端 fds 只会出现在 rlist 中。发送消息应该基于可写 fds,通过遍历 wlist 来完成。但这还有其他问题...

    3. 您始终select() 了解所有客户端 fd 的可写性,即使没有要写入该客户端的待处理消息。最终结果是您的 select() 调用几乎总是会立即返回,并且会浪费 CPU(这有点违背了 select 的目的)

    4. 1234563 /p>

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-20
      • 2012-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-12
      • 1970-01-01
      相关资源
      最近更新 更多