简单的多客户端服务器

2 投票
2 回答
15940 浏览
提问于 2025-04-17 00:12

我正在尝试实现一个简单的服务器,可以同时处理多个客户端。这个服务器应该能够从需要的连接接收数据,处理这些数据,然后再把结果发送给其他客户端。我使用的是Python标准库中的select模块。

这是服务器的代码:

class ProcessingServer:
    def __init__(self, bindaddress="localhost", portname=50001, maxqueue=5):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.bind((bindaddress, portname))
        self.socket.listen(maxqueue)
        self.inputsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.data = ""

    def connect_to_output(self, address, port):
        self.inputsocket.connect((address, port))

    def start(self):
        rsocks = []
        wsocks = []
        rsocks.append(self.socket)
        wsocks.append(self.inputsocket)
        self.socket.accept()

        while True:
            try:
                reads, writes, errs = select.select(rsocks, wsocks, [])
            except:
                return
            for sock in reads:
                if sock == self.socket:
                    client, address  = sock.accept()
                    rsocks.append(client)
                else:
                    self.socket.send(self.data)
                    rsocks.remove(sock) 
            for sock in writes:
               if sock == self.inputsocket:
                    self.data = sock.recv(512)
                    wsocks.remove(sock)
                    print repr(self.data)

这是一个简单的客户端代码:

import socket
mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysocket.connect(("localhost", 50001))
while True:
    data = mysocket.recv(512)
    print repr(data)
mysocket.close()

服务器接收数据的部分运行得很好,但服务器没有任何输出。
我在网络编程方面经验不多,感觉自己好像漏掉了什么。

2 个回答

2

好的...用zeromq来代替吧:

server.py

import zmq
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://127.0.0.1:50001")

while True:
    msg = socket.recv()
    print "Got", msg
    socket.send(msg)

client.py

import zmq
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://127.0.0.1:50001")

for i in range(100):
    msg = "msg %s" % i
    socket.send(msg)
    print "Sending", msg
    msg_in = socket.recv()
2

你的脚本里有一些地方看起来有点奇怪。

通常使用select模块的方式是这样的:你有一个用来监听连接的socket,还有一个socket用来和每个客户端连接。

一开始,只有这个监听连接的socket会被加入到你可能读取的列表中,而可能写入的列表是空的。

调用select.select(potential_readers, potential_writers, potential_errors)会返回三个列表: - 准备好读取的socket - 准备好写入的socket - 出现错误的socket

在准备好读取的socket列表中,如果这个socket是用来监听连接的,那么它必须接受连接,并把新的socket放入可能读取、可能写入和可能出错的列表中。

如果这个socket是其他的,那么就说明这个socket里有数据可以读取。你应该调用sock.recv(length)来获取数据。

如果你想发送数据,应该从select.select返回的写入列表中发送。

错误列表不常用。


现在,关于你问题的解决方案,根据你描述的协议(如果我理解没错),可能看起来像这样:

import socket, select

sock_producer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_producer.bind(('localhost', 5000))
sock_producer.listen(5)
producers = []    

clients = []
sock_consumer_listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Note: different port to differentiate the clients who receive data from the one who sends messages
sock_consumer_listener.bind(('localhost', 5001))

rlist = [sock_producer, sock_listener]
wlist = []
errlist = []

out_buffer = []

while True:
    r, w, err = select.select(rlist, wlist, errlist)
    for sock in r:
        if sock == sock_producer:
            prod, addr = sock.accept()
            producers.append(prod)
            rlist.append(prod)
         elif sock == sock_consumer_listener:
            cons, addr = sock.accept()
            clients.append(cons)
            wlist.append(cons)
         else:
            out_buffer.append(sock.recv(1024))

     out_string = ''.join(out_buffer)
     out_buffer = []

     for sock in w:
         if sock in clients:
             sock.send(out_string)

我没有测试过这段代码,所以可能会有一些错误,但这接近我会怎么做的方式。

撰写回答