2011-08-23 114 views
1

我試圖實現具有多個客戶端的簡單服務器。它應該從必要的套接字接收數據,然後將數據發送到其他客戶端。我使用Python標準庫中的選擇模塊。 這裏的服務器:具有多個客戶端的簡單服務器

class ProcessingServer: 
    def __init__(self, bindaddress="localhost", portname=50001, maxqueue=5): 
     self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.socket.bind((bindaddress, portname)) 
     self.socket.listen(maxqueue) 
     self.inputsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.data = "" 

    def connect_to_output(self, address, port): 
     self.inputsocket.connect((address, port)) 

    def start(self): 
     rsocks = [] 
     wsocks = [] 
     rsocks.append(self.socket) 
     wsocks.append(self.inputsocket) 
     self.socket.accept() 

     while True: 
      try: 
       reads, writes, errs = select.select(rsocks, wsocks, []) 
      except: 
       return 
      for sock in reads: 
       if sock == self.socket: 
        client, address = sock.accept() 
        rsocks.append(client) 
       else: 
        self.socket.send(self.data) 
        rsocks.remove(sock) 
      for sock in writes: 
       if sock == self.inputsocket: 
        self.data = sock.recv(512) 
        wsocks.remove(sock) 
        print repr(self.data) 

這是一個簡單的客戶端:

import socket 
mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
mysocket.connect(("localhost", 50001)) 
while True: 
    data = mysocket.recv(512) 
    print repr(data) 
mysocket.close() 

接收服務器的一部分工作正常,但服務器不會產生任何輸出。 我沒有在網絡編程方面的經驗,感覺就像我錯過了一些東西。

+0

(whispers)__twisted__ –

+0

謝謝,但我想保持儘可能簡單的事情)) – qutron

+0

扭曲遠比使用套接字簡單。你甚至不必擔心線程。 Twisted會爲你做爵士樂。 –

回答

2

有跡象表明,在看上去很奇怪的幾件事情你腳本。

選擇模塊的標準用法如下:您有一個套接字來偵聽連接,並且每個連接與客戶端有一個套接字。

首先,只有這個套接字被添加到您的潛在讀者列表中,而您的潛在作者列表是空的。

調用select.select(potential_readers,potential_writers,potential_errors)將返回3所列出: - 插座讀就緒 - 插座準備寫 - 插座錯誤

在插座準備閱讀的名單,如果套接字是監聽連接的套接字,那麼它必須接受它並將新套接字置於潛在讀取,潛在寫入和潛在錯誤之中。

如果套接字是另一個,那麼有數據要從這個套接字讀取。你應該打電話給sock.recv(長度)

如果你想發送數據,你應該從你的wlist發送select.select返回的wlist。

errlist不經常使用。現在


,對於你的問題,你描述你的協議(如果我深知)方式的解決方案,它可能是這樣的:

import socket, select 

sock_producer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock_producer.bind(('localhost', 5000)) 
sock_producer.listen(5) 
producers = []  

clients = [] 
sock_consumer_listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
# Note: different port to differentiate the clients who receive data from the one who sends messages 
sock_consumer_listener.bind(('localhost', 5001)) 

rlist = [sock_producer, sock_listener] 
wlist = [] 
errlist = [] 

out_buffer = [] 

while True: 
    r, w, err = select.select(rlist, wlist, errlist) 
    for sock in r: 
     if sock == sock_producer: 
      prod, addr = sock.accept() 
      producers.append(prod) 
      rlist.append(prod) 
     elif sock == sock_consumer_listener: 
      cons, addr = sock.accept() 
      clients.append(cons) 
      wlist.append(cons) 
     else: 
      out_buffer.append(sock.recv(1024)) 

    out_string = ''.join(out_buffer) 
    out_buffer = [] 

    for sock in w: 
     if sock in clients: 
      sock.send(out_string) 

我沒有測試過此代碼,以便可能會出現一些錯誤,但這與我將如何去做有關。

+0

+1對_「不同的端口區分接收數據的客戶端和發送消息的客戶端」_是的。有一天,我通過了幾個小時才明白這一點。它在文檔和教程中沒有很好的排列 – eyquem

+0

@Martin:我不明白。我有一個套接字 - 數據的來源。源套接字是一個客戶端套接字,我嘗試在我啓動服務器後立即連接到它。 (在我的例子中是inputsocket)。另一個套接字是偵聽傳入連接的套接字。但在您的示例中有兩個「服務器」套接字 - sock_producer,sock_listener。你能再解釋一下嗎? – qutron

+0

@qutron:數據來源是一個套接字。就我而言,源套接字是製作人。我傾聽,而不是連接到某個地方,但它應該很容易適應(連接而不是聽),並刪除塊'if sock == sock_producer:...' – Martin

2

是啊...用zeromq代替:

server.py

import zmq 
context = zmq.Context() 
socket = context.socket(zmq.REP) 
socket.bind("tcp://127.0.0.1:50001") 

while True: 
    msg = socket.recv() 
    print "Got", msg 
    socket.send(msg) 

client.py

import zmq 
context = zmq.Context() 
socket = context.socket(zmq.REQ) 
socket.connect("tcp://127.0.0.1:50001") 

for i in range(100): 
    msg = "msg %s" % i 
    socket.send(msg) 
    print "Sending", msg 
    msg_in = socket.recv() 
+0

將zeromq放到公共互聯網上安全嗎?截至今年早些時候,情況並非如此,因爲惡意的當事人可能因爲發現格式錯誤的數據而導致聽衆崩潰。 –

+0

不確定你指的是?鏈接?我會想象它會比試圖手動做低級套接字更穩定。如果你想要更強大的東西,扭曲可能是要走的路。 – zeekay

+0

例如,。這裏提到的兩個問題似乎是固定的(遺憾的是,這些鏈接被破壞了,所以這不是很明顯)。我只用了一兩分鐘的搜索就發現了這篇文章。其他搜索可能會出現其他類似的問題。 –