Python TCP 服务器,写入客户端?

标签 python sockets select

我有一个 tcp 服务器,它使用 select 调用来多路复用来自客户端的读取。 我有一个客户端类(MClient),它管理传入数据包的解码

while(1)

    rlist, wlist, xlist = select( input_sockets, output_sockets, [] , 1)

    for insock in rlist: #any clients????

        if insock is server_socket:
            new_socket, addr = server_socket.accept()
            input_sockets.append(new_socket)    
            clients[insock.fileno()] = MClient(new_socket, addr, client_id) #dict of clients        
        else:
            data = insock.recv(512)
            if data:
                clients[insock.fileno()].ProcessPacket(data)
            else:
                input_sockets.remove(insock)
                del clients[insock.fileno()]

    #handle writing to sockets
    for outsock in wlist: 
        ....not done yet



   #do some other stuff not associated with the socket

我对如何处理将数据发送回客户端感到困惑,即如何写入列表“output_sockets”。我正在考虑在 MClient 对象中设置一个标志,表明我有数据要发送回客户端。然后,我将在服务器循环中检查每个客户端以查看是否设置了此标志,然后使用相应的套接字填充output_list。当套接字可用于写入时,我将调用适当的客户端写入函数。

这个方案看起来不太优雅,我想在主服务器循环中处理写入。我该如何实现这个目标?

谢谢

最佳答案

这是我不久前写的一些内容,旨在了解如何使用单个线程处理多个连接。它绝不是完美的,但说明了您想要做什么。客户端对象管理连接的读写流,并确保服务器在正确的 select() 列表中拥有客户端套接字。这实现了一个简单的协议(protocol),其中消息由换行符终止。 PumpXXXX() 函数只是阻止读/写流并管理读/写缓冲区。仅当在缓冲区中找到换行符时才会处理完整消息。

import socket
import select

class Client(object):

    '''This object is created for each client connection.  It tracks
    what has been read, what has been written, and processes complete
    messages terminated by newlines.  It responds by returning the
    original message wrapped in square brackets and terminated by a
    newline. '''

    def __init__(self,who,sock,server):

        '''who - client address
        sock - client socket
        server - server object for this client
        '''

        self.who = who
        self.readbuf = ''
        self.writbuf = ''
        self.server = server
        self.sock = sock

    def close(self):

        '''Removes client from server's reader/writer queues and
        closes the connection.'''

        self.sock.close()
        if self.sock in self.server.readers:
            self.server.readers.remove(self.sock)
        if self.sock in self.server.writers:
            self.server.writers.remove(self.sock)
        self.server.data.pop(self.sock)

    def pumprecv(self):

        '''Server calls pumprecv() when something is readable from the
        client socket.  The data is appended to the client's read
        buffer.mro Complete messages (if any) are then removed from
        the buffer and processed.'''

        try:
            tmp = self.sock.recv(1000)
        except socket.error,e:
            print 'recv',e
            self.close()
        else:                
            if tmp:
                self.readbuf += tmp

                # Complete messages are processed
                while '\n' in self.readbuf:
                    msg,self.readbuf = self.readbuf.split('\n',1)
                    print self.who,msg
                    self.writbuf += '[' + msg + ']\n'
                    # New data to send.  Make sure client is in the
                    # server's writer queue.
                    if self.sock not in self.server.writers:
                        self.server.writers.append(self.sock)
            else:
                self.close()

    def pumpsend(self):
        try:
            # send some data.  tmp is #chars sent (may not be all in writbuf).
            tmp = self.sock.send(self.writbuf)
        except socket.error,e:
            print 'send:',e
            self.close()
        else:
            # Removed sent characters from writbuf.
            self.writbuf = self.writbuf[tmp:]
            # If writbuf is empty, remove socket from server's write queue.
            if not self.writbuf:
                self.server.writers.remove(self.sock)

class Server(object):
    def __init__(self,ip='127.0.0.1',port=9999):
        self.ssock = socket.socket()
        self.ssock.bind((ip,port))
        self.ssock.listen(5)
        self.readers = [self.ssock]
        self.data = {}
        self.writers = []
        self.quit = False

    def pumpaccept(self):

        '''Called when server socket is readable to accept a
        connection and create a Client object.'''

        csock,who = self.ssock.accept()
        print 'Connected %s:%d' % who
        self.readers.append(csock)
        self.data[csock] = Client(who,csock,self)

    def serve(self):
        while not self.quit or self.writers:
            readable,writable,other = select.select(self.readers,self.writers,[],1.0)
            # Operate on copies of the queues since the pumpXXX() commands can modify the lists.
            if self.ssock in readable[:]:
                self.pumpaccept()
                readable.remove(self.ssock)
            for reader in readable[:]:
                self.data[reader].pumprecv()
            for writer in writable[:]:
                self.data[writer].pumpsend()

            if not readable and not writable and not other:
                print '.',

if __name__ == '__main__':
    srv = Server()
    srv.serve()

我通过在一个控制台中启动服务器并在其他控制台中运行以下代码来测试多个连接来对此进行测试。建立多个连接,从不同窗口交替发送,并发送部分消息以查看服务器如何响应。

>>> from socket import *
>>> s=socket()
>>> s.connect(('localhost',9999))
>>> s.send('one\ntwo\nthree')
13
>>> s.send('\nfour\n')
6
>>> s.recv(1024)
'[one]\n[two\three]\n[four]\n'
>>> s.close()

输出应类似于:

. . . . . . . . . . . . . . . . . . . Connected 127.0.0.1:1514
. . . . . . . . . ('127.0.0.1', 1514) one
. . . . . . . ('127.0.0.1', 1514) two
. . . ('127.0.0.1', 1514) three
('127.0.0.1', 1514) four
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

关于Python TCP 服务器,写入客户端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3043394/

相关文章:

python - Webapp2 session 在请求之间丢失

sockets - Linux - 带有 FIONREAD 的 ioctl 始终为 0

c++ - 在qt/linux中如何获取ip地址?

mysql - 在 Laravel 中选择

c - 选择时的套接字阻止和超时

python - 基于动态索引条件向 Pandas DataFrame 添加列

python - 获得整数数组汉明距离的最快方法

java - 如何将套接字存储在数据库中?

mysql - 如何在没有连续切割的情况下使用 mysql group_concat(concat())

python - 使用列表理解分解此列表