需要帮助在两个套接字之间创建TCP中继 [英] Need help creating a TCP relay between two sockets

查看:60
本文介绍了需要帮助在两个套接字之间创建TCP中继的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下情况:

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 中继到用户.这是在两个方向上发生的.

Essentially, MyApp initiates communication with SomeServer (SomeServer(S) <-> (C)MyApp) and once some authentication routines are successful MyApp(S) starts waiting for (C)User to connect. As soon as User connects, MyApp relays data from SomeServer to User. This happens in both directions.

我的 SomeServer(S)<-(C)MyApp 正常运行,但是我无法获得 MyApp(S)<->(C)User.我可以看到用户已连接到 MyApp(S),但是无法中继数据!

I have SomeServer(S) <-> (C)MyApp working perfectly, but I'm not able to get MyApp(S) <-> (C)User working. I get as far as User connecting to MyApp(S), but can't get data relayed!

好的,我希望这很清楚;)现在,让我显示 MyApp 的代码. SomeServer User 的实现与解决我的问题无关,因为两者都无法修改.

Ok, I hope that's some what clear ;) Now let me show my code for MyApp. Btw the implementation of SomeServer and User are not relevant for solving my question, as neither can be modified.

我已注释我的代码,指出我在哪里遇到问题.哦,我还要指出的是,如有必要,我可以毫无问题地为整个其他服务器部分"剪贴一些其他代码.这是一个POC,所以我的主要重点是使功能起作用而不是编写高效的代码.谢谢您的时间.

I have commented my code indicating where I'm experiencing issues. Oh, I should also mention that I have no problem scrapping the whole "Server Section" for some other code if necessary. This is a POC, so my main focus is getting the functionality working rather than writing efficient code. Thanks for you time.

''' 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我用您的代码(未显示)替换了完整的模块,并重新添加了身份验证等所需的所有细节.

@samplebias I replaced my complete module with your code (not shown) and I have re-added all the bits and pieces that I need for authentication etc.

在这一点上,我得到的结果与上面我自己的代码相同.我的意思是MyApp(或您代码中的Server)已连接到SomeServer并来回传递数据.到目前为止一切都很好.当用户(或客户端应用程序)连接到本地主机8080时,将运行以下代码:

At this point I'm getting the same result, as with my own code above. What I mean is that MyApp (or Server in your code) is connected to SomeServer and passing data back and forth. Everything is fine thus far. When User (or client application) connects to localhost 8080, this code is run:

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()永远不会运行.

So, Server is not relaying data to User. I added print statements throughout the User class to see what is run and init is the only thing. handle_read() never runs.

这是为什么?

推荐答案

该代码很难遵循,我敢肯定有一些bug.为了handle_read()中的示例将MyAppClient的原始套接字 self.socket 传递给中继服务器.最后,MyAppClient和RelayConnection都在同一个套接字上工作.

The code is a bit hard to follow, and I'm sure there are a few bugs. For example in handle_read() you're passing MyAppClient's raw socket self.socket to RelayServer. You end up with both MyAppClient and RelayConnection working on the same socket.

而不是尝试对我放在一起的原始代码提出错误修复建议一个示例,它可以实现您的代码意图,并且更加简洁,易于理解.我已经测试了它与IMAP服务器的通信,并且可以正常工作,但是省略了一些简洁起见(错误处理,在所有情况下都正确处理close()等).

Rather than attempt to suggest bug fixes to the original code I put together an example which does what your code intents and is cleaner and easier to follow. I've tested it talking to an IMAP server and it works, but omits some things for brevity (error handling, proper close() handling in all cases, etc).

  • 服务器启动与"someserver"的连接.一旦连接它会启动 Listener .
  • 侦听器在端口8080上侦听并仅接受1个连接,并创建一个用户,并将其引用传递给服务器.监听器拒绝所有其他用户处于活动状态时客户端连接.
  • 用户将所有数据转发到服务器,反之亦然.评论指示应该在哪里插入身份验证.
  • Server initiates the connection to "someserver". Once it connects it starts the Listener.
  • Listener listens on port 8080 and accepts only 1 connection, creates a User, and passes it a reference to Server. Listener rejects all other client connections while User is active.
  • User forwards all data to Server, and vice versa. The comments indicate where the authentication should be plugged in.

来源:

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

这篇关于需要帮助在两个套接字之间创建TCP中继的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆