Skip to main content
 首页 » 编程设计

python之如何使用 Twisted 创建非 http 代理

2025年05月04日21lyj

如何使用 Twisted 创建非 http 代理。相反,我想为完全由二进制数据组成的 Terraria 协议(protocol)做这件事。我看到他们有一个内置的 HTTP 连接代理,但是这个应用程序需要更像一个入口点,它被转发到一个设置的服务器(几乎像 IRC 上的 BNC)。 我不知道如何从一个连接读取数据并将其发送到另一个连接。

我已经尝试使用套接字来完成这项任务,但是阻塞式 recv 和 send 方法效果不佳,因为两个连接需要同时处于事件状态。

请您参考如下方法:

有几种不同的方法可以在 Twisted 中创建代理。基本技术建立在对等互连之上,通过在两个不同的端口上采用两种不同的协议(protocol),并以某种方式将它们粘合在一起,以便它们可以相互交换数据。

最简单的代理是端口转发器。带有端口转发器实现的 Twisted ships,参见 http://twistedmatrix.com/documents/current/api/twisted.protocols.portforward.html对于(文档不足的)类 ProxyClient 和 ProxyServer,尽管实际来源在 http://twistedmatrix.com/trac/browser/tags/releases/twisted-11.0.0/twisted/protocols/portforward.py通读可能更有用。从那里,我们可以看到 Twisted 中代理的基本技术:

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

当代理协议(protocol)接收到数据时,它会将数据发送给另一端的对等方。就是这样!非常简单。当然,您通常需要一些额外的设置...让我们看一下我之前编写的几个代理。

这是 Darklight 的代理,Darklight 是我编写的一个点对点小系统。它正在与后端服务器对话,并且它只想在数据与预定义的 header 不匹配时代理数据。你可以看到它使用 ProxyClientFactory 和端点(花哨的 ClientCreator,基本上)开始代理,当它接收到数据时,它有机会在继续之前检查它,或者继续代理或切换协议(protocol)。

class DarkServerProtocol(Protocol): 
    """ 
    Shim protocol for servers. 
    """ 
 
    peer = None 
    buf = "" 
 
    def __init__(self, endpoint): 
        self.endpoint = endpoint 
        print "Protocol created..." 
 
    def challenge(self, challenge): 
        log.msg("Challenged: %s" % challenge) 
        # ...omitted for brevity... 
        return is_valid(challenge) 
 
    def connectionMade(self): 
        pcf = ProxyClientFactory() 
        pcf.setServer(self) 
        d = self.endpoint.connect(pcf) 
        d.addErrback(lambda failure: self.transport.loseConnection()) 
 
        self.transport.pauseProducing() 
 
    def setPeer(self, peer): 
        # Our proxy passthrough has succeeded, so we will be seeing data 
        # coming through shortly. 
        log.msg("Established passthrough") 
        self.peer = peer 
 
    def dataReceived(self, data): 
        self.buf += data 
 
        # Examine whether we have received a challenge. 
        if self.challenge(self.buf): 
            # Excellent; change protocol. 
            p = DarkAMP() 
            p.factory = self.factory 
            self.transport.protocol = p 
            p.makeConnection(self.transport) 
        elif self.peer: 
            # Well, go ahead and send it through. 
            self.peer.transport.write(data) 

这是一段相当复杂的代码块,它采用两个 StatefulProtocol 并将它们相当有力地粘合在一起。这是来自 VNC 代理(准确地说是 https://code.osuosl.org/projects/twisted-vncauthproxy),它需要其协议(protocol)在准备好加入之前做很多预认证工作。这种代理是最坏的情况;为了提高速度,您不想与通过代理的数据进行交互,但您需要事先进行一些设置。

def start_proxying(result): 
    """ 
    Callback to start proxies. 
    """ 
 
    log.msg("Starting proxy") 
    client_result, server_result = result 
    success = True 
    client_success, client = client_result 
    server_success, server = server_result 
 
    if not client_success: 
        success = False 
        log.err("Had issues on client side...") 
        log.err(client) 
 
    if not server_success: 
        success = False 
        log.err("Had issues on server side...") 
        log.err(server) 
 
    if not success: 
        log.err("Had issues connecting, disconnecting both sides") 
        if not isinstance(client, Failure): 
            client.transport.loseConnection() 
        if not isinstance(server, Failure): 
            server.transport.loseConnection() 
        return 
 
    server.dataReceived = client.transport.write 
    client.dataReceived = server.transport.write 
    # Replay last bits of stuff in the pipe, if there's anything left. 
    data = server._sful_data[1].read() 
    if data: 
        client.transport.write(data) 
    data = client._sful_data[1].read() 
    if data: 
        server.transport.write(data) 
 
    server.transport.resumeProducing() 
    client.transport.resumeProducing() 
    log.msg("Proxying started!") 

所以,既然我已经解释过了......

我也写了 Bravo。如,http://www.bravoserver.org/ .所以我对 Minecraft 有所了解,因此对 Terraria 也有所了解。您可能希望在两侧解析通过您的代理的数据包,因此您的实际代理可能开始看起来像这样,但随着您开始了解您正在代理的数据,它会迅速发展。希望这足以让您入门!