2011-04-04 90 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) #...