2011-04-04 140 views
0

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

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

Server代码:

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

回答

0

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

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

print message 
globalTest() 
print message 

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

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

您从不初始化消息,所以message += temp将抛出UnboudLocalError表示它在分配值之前被引用。 (可能是问题#1的原因)另外,为什么在第一个位置追加字符串,这意味着每次发送内容时,整个对话都会发送出去。

此外,不要手动获取和释放锁,使用更清洁。

with lock: 
    message += temp 
2

这是更简单,更好地执行这样的事情使用Twisted,使您可以处理多个客户端同时在一个单独的线程,以及提供一个更好的API。

这里是你如何编写使用双绞线(在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对象被创建,事件循环调用它的启动方式/停止事件和当从客户端收到一条线时。在这种情况下,它只是将收到的每一行发送给系统中的所有客户端。由于它在单线程中运行,因此不需要锁。

0

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