Нужна помощь в создании TCP-реле между двумя сокетами - PullRequest
3 голосов
/ 12 марта 2011

У меня следующая ситуация:

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

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

По существу, MyApp инициирует связь с SomeServer ( SomeServer (S) <-> (C) MyApp ) и после успешного завершения некоторых процедур аутентификации MyApp (S) начинает ждать ( C) пользователя для подключения. Как только пользователь подключается, MyApp передает данные с SomeServer на пользователя . Это происходит в обоих направлениях.

У меня SomeServer (S) <-> (C) MyApp работает отлично, но я не могу получить MyApp (S) <-> (C) Пользователь за работой. Пользователь подключается к MyApp (S) , но не может передать данные!

Хорошо, надеюсь, это кое-что прояснит;) Теперь позвольте мне показать мой код для MyApp . Кстати, реализация SomeServer и User не имеет значение для решения моего вопроса, так как ни один из них не может быть изменен.

Я прокомментировал свой код, указав, где у меня возникают проблемы. О, я должен также упомянуть, что у меня нет проблем с утилизацией всего "раздела сервера" для какого-то другого кода, если это необходимо Это 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()

EDIT:

@ samplebias Я заменил свой полный модуль на ваш код (не показан) и заново добавил все биты и кусочки, которые мне нужны для аутентификации и т. Д.

На данный момент я получаю тот же результат, что и с моим собственным кодом выше. Я имею в виду, что MyApp (или сервер в вашем коде) подключен к SomeServer и передает данные туда и обратно. Пока все хорошо. Когда пользователь (или клиентское приложение) подключается к localhost 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)

Итак, Сервер не передает данные Пользователю. Я добавил операторы print во всем классе User, чтобы увидеть, что выполняется, и init - единственное. handle_read () никогда не запускается.

Почему это?

1 Ответ

4 голосов
/ 12 марта 2011

Код немного сложен для отслеживания, и я уверен, что есть несколько ошибок.Например, в handle_read () вы передаете необработанный сокет MyAppClient self.socket в RelayServer.В конечном итоге MyAppClient и RelayConnection работают в одном сокете.

Вместо того, чтобы пытаться предлагать исправления ошибок в исходном коде, я собрал пример, который делает то, что предназначен для вашего кода, а также является более чистым и легким для понимания.Я проверил его, общаясь с сервером IMAP, и он работает, но для краткости опускает некоторые вещи (обработку ошибок, правильное закрытие () во всех случаях и т. Д.).

  • Сервер инициирует соединение с «someserver».После подключения он запускает Listener .
  • Listener прослушивает порт 8080 и принимает только 1 соединение, создает User и передает егоссылка на Сервер . Слушатель отклоняет все остальные клиентские подключения, пока Пользователь активен.
  • Пользователь пересылает все данные на Сервер и наоборотнаоборот.В комментариях указывается, где должна быть включена аутентификация.

Источник:

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()
...