【问题标题】:Multi-threaded multi-client server in pythonpython中的多线程多客户端服务器
【发布时间】:2011-07-29 11:27:54
【问题描述】:

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

  1. 第一个发送消息的客户端立即断开连接。
  2. 另一个客户端没有收到第一个客户端发送的消息。

服务器代码:

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

【问题讨论】:

    标签: python multithreading sockets echo


    【解决方案1】:

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

    【讨论】:

      【解决方案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 对象,并且事件循环会调用它的方法来处理启动/停止事件以及从客户端接收到一行。在这种情况下,它只是将接收到的每一行发送给系统中的所有客户端。由于它在单线程中运行,因此不需要锁。

      【讨论】:

        【解决方案3】:

        这不是您使用global 的方式。当你定义一个方法时,在方法范围内,你使用全局命令来引用更高范围的变量。

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

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

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

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

        另外,不要手动获取和释放锁,使用 with 更干净。

        with lock:
          message += temp
        

        【讨论】:

          猜你喜欢
          • 2021-12-01
          • 2014-12-21
          • 2011-04-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-10
          • 2019-05-17
          • 2015-01-09
          相关资源
          最近更新 更多