2011-03-11 114 views
3

之間的TCP中繼我有以下情況:需要幫助建立兩個插座

SomeServer(S) <-> (C)MyApp(S) <-> (C)User 

(S) represents a server socket 
(C) represents a client socket 

從本質上講,MyApp的啓動與SomeServerSomeServer(S)<通信 - >(C)MyApp的 )並且一旦一些認證例程成功MyApp(S)開始等待(C)用戶連接。 用戶連接,MyApp中繼數據SomeServer用戶。這發生在兩個的方向。

我有SomeServer(S)< - >(C)MyApp的完美的工作,但我沒能得到MyApp的(S)< - >(C)用戶工作。我得到儘可能用戶連接到MyApp(S),但無法獲得數據中繼!

好的,我希望這是一些清晰的;)現在讓我顯示我的代碼爲MyApp。 btw執行SomeServer用戶不是有關解決我的問題,因爲都不可以修改。

我評論了我的代碼,指出我遇到問題。哦,我還應該提到,如果有必要,我沒有問題將整個「服務器部分」廢棄爲其他一些代碼。這是一個POC,所以我的主要焦點是讓功能工作,而不是編寫高效的代碼。謝謝你的時間。

''' MyApp.py module ''' 

import asyncore, socket 
import SSL 

# Client Section 
# Connects to SomeServer 

class MyAppClient(asyncore.dispatcher): 

    def __init__(self, host, port): 
     asyncore.dispatcher.__init__(self) 
     self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.connect((host, port)) 

    connectionPhase = 1 
    def handle_read(self): 
     print "connectionPhase =", self.connectionPhase 

    # The following IF statements may not make sense 
    # as I have removed code irrelevant to this question 

    if self.connectionPhase < 3: # authentication phase 
      data = self.recv(1024) 
      print 'Received:', data 

      # Client/Server authentication is handled here 
      # Everything from this point on happens over 
      # an encrypted socket using SSL 

      # Start the RelayServer listening on localhost 8080 
      # self.socket is encrypted and is the socket communicating 
      # with SomeServer 

      rs = RelayServer(('localhost', 8080), self.socket) 
      print 'RelayServer started' 

     # connectionPhase = 3 when this IF loop is done 

     elif self.connectionPhase == 3: # receiving data for User 
      data = self.recv(1024) 

      print 'Received data - forward to User:', data 

      # Forward this data to User 
      # Don't understand why data is being read here 
      # when the RelayServer was instantiated above 

# Server Section 
# Connects to User 

class RelayConnection(asyncore.dispatcher): 
    def __init__(self, client, sock): 
     asyncore.dispatcher.__init__(self) 
     self.client = client 
     print "connecting to %s..." % str(sock) 

    def handle_connect(self): 
     print "connected." 
     # Allow reading once the connection 
     # on the other side is open. 
     self.client.is_readable = True 


    # For some reason this never runs, i.e. data from SomeServer 
    # isn't read here, but instead in MyAppClient.handle_read() 
    # don't know how to make it arrive here instead as it should 
    # be relayed to User 

    def handle_read(self): 
     self.client.send(self.recv(1024)) 

class RelayClient(asyncore.dispatcher): 
    def __init__(self, server, client, sock): 
     asyncore.dispatcher.__init__(self, client) 
     self.is_readable = False 
     self.server = server 
     self.relay = RelayConnection(self, sock) 

    def handle_read(self): 
     self.relay.send(self.recv(1024)) 

    def handle_close(self): 
     print "Closing relay..." 
     # If the client disconnects, close the 
     # relay connection as well. 
     self.relay.close() 
     self.close() 

    def readable(self): 
     return self.is_readable 

class RelayServer(asyncore.dispatcher): 
    def __init__(self, bind_address, MyAppClient_sock): 
     asyncore.dispatcher.__init__(self) 
     self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.bind(bind_address) 
     self.MyAppClient_sock = MyAppClient_sock 
     print self.MyAppClient_sock 
     self.listen(1) 

    def handle_accept(self): 
     conn, addr = self.accept() 
     RelayClient(self, conn, self.MyAppClient_sock) 

if __name__ == "__main__": 
    # Connect to host 
    # First connection stage 
    connectionPhase = 1 
    c = MyAppClient('host', port) # SomeServer's host and port 

    asyncore.loop() 

編輯:

@samplebias我代替我的完整模塊與您的代碼(未顯示)和我已經重新添加所有位,而我需要進行身份驗證等片

在這一點上,我得到了與上面我自己的代碼相同的結果。我的意思是MyApp(或代碼中的服務器)連接到SomeServer並來回傳遞數據。目前爲止一切都很好。當用戶(或客戶端應用程序)連接到本地主機8080,運行這些代碼:

if not self.listener: 
    self.listener = Listener(self.listener_addr, self) 

,但它沒有運行

# if user is attached, send data 
    elif self.user: 
     print 'self.user' 
     self.user.send(data) 

因此,服務器沒有數據中繼到用戶。我在整個User類中添加了打印語句以查看運行的內容,並且init是唯一的。 handle_read()永不運行。

這是爲什麼?

+0

你應該看看[PEP8](http://www.python.org/dev/peps/pep- 0008 /),如果你遵循它,你的代碼不會打破SO的代碼標記;-) – 2011-03-12 00:53:43

回答

3

該代碼有點難以遵循,我敢肯定有一些錯誤。對於handle_read()中的 示例,您將MyAppClient的原始套接字self.socket傳遞給 RelayServer。您最終將在同一個套接字上使用MyAppClient和RelayConnection。

而不是嘗試建議對原始代碼的錯誤修復,我把它放在一起 這是一個例子,它代碼意圖更清晰,更易於遵循。 我測試過它與IMAP服務器通信並且它可以工作,但爲了簡潔(錯誤處理,在所有情況下適當的close()處理等),省略了一些 事情。

  • 服務器啓動到「someserver」的連接。一旦它連接 它啓動聽衆
  • 監聽監聽端口8080和只接受1連接,創建一個用戶, 並將其傳遞到服務器的參考。 收聽者拒絕所有其他 客戶端連接,而用戶處於活動狀態。
  • 用戶轉發所有數據到服務器,反之亦然。該意見 指明認證應插

來源:

import asyncore 
import socket 

class User(asyncore.dispatcher_with_send): 

    def __init__(self, sock, server): 
     asyncore.dispatcher_with_send.__init__(self, sock) 
     self.server = server 

    def handle_read(self): 
     data = self.recv(4096) 
     # parse User auth protocol here, authenticate, set phase flag, etc. 
     # if authenticated, send data to server 
     if self.server: 
      self.server.send(data) 

    def handle_close(self): 
     if self.server: 
      self.server.close() 
     self.close() 

class Listener(asyncore.dispatcher_with_send): 

    def __init__(self, listener_addr, server): 
     asyncore.dispatcher_with_send.__init__(self) 
     self.server = server 
     self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.set_reuse_addr() 
     self.bind(listener_addr) 
     self.listen(1) 

    def handle_accept(self): 
     conn, addr = self.accept() 
     # this listener only accepts 1 client. while it is serving 1 client 
     # it will reject all other clients. 
     if not self.server.user: 
      self.server.user = User(conn, self.server) 
     else: 
      conn.close() 

class Server(asyncore.dispatcher_with_send): 

    def __init__(self, server_addr, listener_addr): 
     asyncore.dispatcher_with_send.__init__(self) 
     self.server_addr = server_addr 
     self.listener_addr = listener_addr 
     self.listener = None 
     self.user = None 

    def start(self): 
     self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.connect(self.server_addr) 

    def handle_error(self, *n): 
     self.close() 

    def handle_read(self): 
     data = self.recv(4096) 
     # parse SomeServer auth protocol here, set phase flag, etc. 
     if not self.listener: 
      self.listener = Listener(self.listener_addr, self) 
     # if user is attached, send data 
     elif self.user: 
      self.user.send(data) 

    def handle_close(self): 
     if self.user: 
      self.user.server = None 
      self.user.close() 
      self.user = None 
     if self.listener: 
      self.listener.close() 
      self.listener = None 
     self.close() 
     self.start() 

if __name__ == '__main__': 
    app = Server(('someserver', 143), ('localhost', 8080)) 
    app.start() 
    asyncore.loop() 
+0

謝謝你的例子!請參閱上面我的帖子的編輯。 – joshu 2011-03-12 20:54:51

+0

@yonatan當我對SomeServer和User協議瞭解不多時,幫助很難。你能否提供關於每個剛建立連接後交換的消息的更多信息。例如,當客戶端連接到端口8080時,服務器是否應該向其發送問候消息?如果是這樣,Listener.handle_accept應該在構建User之後執行'self.server.user.send(greeting_data)'。 – samplebias 2011-03-12 21:56:02

+0

對於遲到的回覆感到抱歉。你的一個班輪正是失蹤的!我不能要求更好的幫助。您的示例代碼完美無瑕!非常感謝你解決了我一直在苦苦掙扎的2周時間:D:D – joshu 2011-03-14 22:00:39