2

我需要的是一种中间人实现:我需要一个服务器,它接收来自客户端的连接(具有不同长度的二进制数据)并将流转发到它连接到的服务器(充当客户端),并且然后将数据从它所连接的服务器发送回客户端。

它实际上位于客户端和服务器之间,并传递它们交换的数据(这是一个流,因此它不断地从一侧获取并发送到另一侧)。
服务器是静态的,所以它总是一样的,它的地址甚至可以硬编码;但是,当客户端断开连接时,该服务器也必须断开与“真实”服务器的连接。

我一直在环顾四周,但找不到这样一个简单问题的解决方案或示例。

我编写的代码实际上可以工作,但我还没有设法找到如何将引用放入“这是您分配的客户端”的服务器部分,或放入“这是您的服务器”的客户端。这是我的代码:

#!/usr/bin/env python

from twisted.internet import protocol, reactor
from twisted.protocols import basic

client = None
server = None

class ServerProtocol(protocol.Protocol):
    def connectionMade(self):
        global server
        factory = protocol.ClientFactory()
        factory.protocol = ClientProtocol
        server = self
        reactor.connectTCP('localhost', 1324, factory)

    def dataReceived(self, data):
        global client
        client.transport.write(data)

class ClientProtocol(protocol.Protocol):
    def connectionMade(self):
        global client
        # Here's the instance of the client
        client = self

    def dataReceived(self, data):
        global server
        server.transport.write(data)

def main():
    import sys
    from twisted.python import log
    log.startLogging(sys.stdout)
    factory = protocol.ServerFactory()
    factory.protocol = ServerProtocol

    # Here's the instance of the server
    server = ServerProtocol

    reactor.listenTCP(2593, factory)
    reactor.run()

if __name__ == '__main__':
    main()

现在,关键是实例不能包含在全局对象中,而应该放在两个类中:如何?

4

2 回答 2

4

我已经设法自己解决了这个问题,为了将来的参考(或帮助遇到这个问题的其他人),这是我用来解决它的代码。

我认为我的解决方案和 jedwards 所提供的解决方案都有效;现在我只需要多研究他自己的一点,以确保我所做的是正确的:这是我第一个使用 Twisted 框架的应用程序,研究别人的解决方案是学习新东西的方法!:)

#!/usr/bin/env python

from twisted.internet import protocol, reactor
from twisted.protocols import basic

class ServerProtocol(protocol.Protocol):
    def __init__(self):
        self.buffer = None
        self.client = None

    def connectionMade(self):
        factory = protocol.ClientFactory()
        factory.protocol = ClientProtocol
        factory.server = self

        reactor.connectTCP('gameserver16.gamesnet.it', 2593, factory)

    def dataReceived(self, data):
        if (self.client != None):
            self.client.write(data)
        else:
            self.buffer = data

    def write(self, data):
        self.transport.write(data)
        print 'Server: ' + data.encode('hex')

class ClientProtocol(protocol.Protocol):
    def connectionMade(self):
        self.factory.server.client = self
        self.write(self.factory.server.buffer)
        self.factory.server.buffer = ''

    def dataReceived(self, data):
        self.factory.server.write(data)

    def write(self, data):
        self.transport.write(data)
        print 'Client: ' + data.encode('hex')

def main():
    import sys
    from twisted.python import log

    log.startLogging(sys.stdout)

    factory = protocol.ServerFactory()
    factory.protocol = ServerProtocol

    reactor.listenTCP(2593, factory)
    reactor.run()

if __name__ == '__main__':
    main()
于 2013-03-26T18:55:04.567 回答
3

考虑这种方法

#!/usr/bin/env python

import sys
from twisted.internet import reactor
from twisted.internet.protocol import ServerFactory, ClientFactory, Protocol
from twisted.protocols import basic
from twisted.python import log

LISTEN_PORT = 2593
SERVER_PORT = 1234


class ServerProtocol(Protocol):
    def connectionMade(self):
        reactor.connectTCP('localhost', SERVER_PORT, MyClientFactory(self))

    def dataReceived(self, data):
        self.clientProtocol.transport.write(data)

class ClientProtocol(Protocol):
    def connectionMade(self):
        # Pass ServerProtocol a ref. to ClientProtocol
        self.serverProtocol.clientProtocol = self;  

    def dataReceived(self, data):
        self.serverProtocol.transport.write(data)

class MyServerFactory(ServerFactory):
    protocol = ServerProtocol
    def buildProtocol(self, addr):
        # Create ServerProtocol
        p = ServerFactory.buildProtocol(self, addr)
        return p

class MyClientFactory(ClientFactory):
    protocol = ClientProtocol
    def __init__(self, serverProtocol_):
        self.serverProtocol = serverProtocol_

    def buildProtocol(self, addr):
        # Create ClientProtocol
        p = ClientFactory.buildProtocol(self,addr)
        # Pass ClientProtocol a ref. to ServerProtocol
        p.serverProtocol = self.serverProtocol
        return p

def main():
    log.startLogging(sys.stdout)

    reactor.listenTCP(LISTEN_PORT, MyServerFactory())
    reactor.run()

if __name__ == '__main__':
    main()

ServerProtcol 实例将自身的引用传递给 MyClientFactory 构造函数,然后它设置告诉 ClientProtcol 它与哪个 ServerProtocol 实例相关联。

同样,当 ClientProtocol 连接建立时,它使用它对 ServerProtocol 的引用来告诉 ServerProtocol 使用什么 ClientProtocol。

注意:此代码中没有错误检查,因此如果出现问题(例如,如果真实服务器未在侦听),您可能会遇到有关 NoneType 的错误。

重要的几行是:

reactor.connectTCP('localhost', SERVER_PORT, MyClientFactory(self))
#...
def __init__(self, serverProtocol_):
    self.serverProtocol = serverProtocol_

在这里,您将对 ServerProtocol 的引用传递给 MyClientFactory 构造函数。它将这个引用存储在一个成员变量中。您这样做是为了在客户端工厂创建 ClientProtocol 时,它可以将引用传递给:

# Pass ClientProtocol a ref. to ServerProtocol
p.serverProtocol = self.serverProtocol

然后,一旦从您的脚本连接到真实服务器,就会发生相反的情况。ClientProtocol 为 ServerProtocol 提供了对其自身的引用:

# Pass ServerProtocol a ref. to ClientProtocol
self.serverProtocol.clientProtocol = self;

最后,两个协议在收到数据时使用彼此存储的引用来发送数据:

def dataReceived(self, data):
    self.clientProtocol.transport.write(data)
#...
def dataReceived(self, data):
    self.serverProtocol.transport.write(data)
于 2013-03-26T16:36:33.887 回答