python中的多线程多客户端服务器

时间:2011-04-04 20:35:14

标签: python multithreading sockets echo

我正在python中编写一个多线程,多客户端服务器。多个用户可以使用telnet连接到它,并基本上将其用作聊天服务器。我可以通过telnet连接两个客户端,但我遇到了以下两个问题:

  1. 发送邮件的第一个客户端会立即断开连接。
  2. 其他客户端不接收第一个客户端发送的消息。
  3. 服务器代码:

    import os
    import sys
    import socket
    import thread
    
    port = 1941
    global message
    global lock
    global file
    
    def handler(connection):
        while 1:
                file = connection.makefile()
                file.flush()
                temp = file.readline()
                if temp == 'quit':
                    break
                lock.acquire()
                message += temp
                lock.release()
                file.write(message)
        file.close()
    
    acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    acceptor.bind(('', port))
    acceptor.listen(10)
    lock = thread.allocate_lock()
    
    while 1:
        connection, addr = acceptor.accept()
        thread.start_new_thread(handler, (connection,))
    

    好的,我听了unholysampler,现在我有了这个。我现在可以连接两个客户端并输入消息,但是它们没有被发送/接收(我不知道是哪一个)。

    import os
    import sys
    import socket
    import thread
    
    port = 1953
    
    def handler(connection):
        global message
        global filelist
        filelist = []
        file = connection.makefile()
        file.flush()
        filelist.append(file)
        message = ''
        while 1:
            i = 0
            while i < (len(filelist)):
                filelist[i].flush()
                temp = filelist[i].readline()
    
                if temp == 'quit':
                    break
    
                with lock:
                    message += temp
    
                i = i + 1
        file.close()
    
    global lock
    acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    acceptor.bind(('', port))
    acceptor.listen(10)
    lock = thread.allocate_lock()
    
    while 1:
        connection, addr = acceptor.accept()
        thread.start_new_thread(handler, (connection,))
    

3 个答案:

答案 0 :(得分:2)

使用Twisted实现此类事情要简单得多,它可以让您在单个线程中同时处理多个客户端,并提供更好的API。

以下是使用Twisted编写聊天服务器的方法(chatserver.py中的完整示例):

class MyChat(basic.LineReceiver):
    def connectionMade(self):
        print "Got new client!"
        self.factory.clients.append(self)

    def connectionLost(self, reason):
        print "Lost a client!"
        self.factory.clients.remove(self)

    def lineReceived(self, line):
        print "received", repr(line)
        for c in self.factory.clients:
            c.message(line)

    def message(self, message):
        self.transport.write(message + '\n')

对于每个用户,创建一个MyChat对象,并且事件循环调用其启动/停止事件的方法以及从客户端收到一行时。在这种情况下,它只是将它接收的每一行发送给系统中的所有客户端。由于它在单个线程中运行,因此不需要锁定。

答案 1 :(得分:0)

这不是你使用global的方式。在方法范围内定义方法时,可以使用global命令对变量引用更高范围的变量。

message = 1
def globalTest():
  global message
  message += 1
  print message

print message
globalTest()
print message

每次迭代循环时,都会为连接创建一个新的文件对象。你想在循环开始之前做到这一点,所以你只做了一次。

您正在读取和写入同一文件对象。这意味着它只是一个echo服务器。你永远不会给thread1一个对thread2文件的引用。尝试为套接字文件使用一个全局变量将不起作用,因为您永远不会知道它实际指向哪个套接字。 (问题#2)

您永远不会初始化消息,因此message += temp会抛出一个UnboudLocalError,表示在分配值之前它已被引用。 (可能是问题#1的原因)另外,为什么要首先附加字符串,这意味着每次发送内容时,都会发送整个会话。

另外,请不要手动获取和释放锁定,使用清洁剂。

with lock:
  message += temp

答案 2 :(得分:0)

我认为你需要在每个连接之前调用s.listen。这是把它放在无限循环中。 while True: acceptor.listen(1) #...