如何使用Twisted创建非http代理。相反,我想为Terraria协议做这件事,该协议完全由二进制数据构成。我看到他们有一个内置的HTTP连接代理,但是这个应用程序需要更像是一个转发到设置服务器的入口点(几乎就像IRC上的BNC)。 我无法弄清楚如何从一个连接读取数据并将其发送到另一个连接。
我已经尝试使用套接字执行此任务,但阻塞的recv和send方法不能正常工作,因为两个连接需要同时处于活动状态。
答案 0 :(得分:6)
在Twisted中有几种不同的方法来创建代理。基本技术建立在对等上,通过在两个不同的端口上采用两种不同的协议,并以某种方式将它们粘合在一起,以便它们可以相互交换数据。
最简单的代理是端口转发器。具有端口转发器实现的扭曲船舶,请参阅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)
当代理协议接收数据时,它会将其发送给另一方的对等方。而已!非常简单。当然,你通常需要一些额外的设置...让我们看一下我之前写的几个代理。
这是Darklight的代理,这是我写的一个小对等系统。它正在与后端服务器通信,如果数据与预定义的标头不匹配,它只想代理数据。您可以看到它使用ProxyClientFactory
和端点(基本上是花式ClientCreator
)来开始代理,当它接收数据时,它有机会在继续之前检查它,以保持代理或切换协议
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
s并将它们强有力地粘合在一起。这是来自VNC代理(确切地说是https://code.osuosl.org/projects/twisted-vncauthproxy),它需要其协议在准备加入之前执行大量预认证。这种代理是最糟糕的情况;对于速度,您不希望与通过代理的数据进行交互,但您需要事先进行一些设置。
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有所了解。您可能希望解析通过代理双方传输的数据包,因此您的实际代理可能会看起来像这样,但随着您开始理解您正在代理的数据,它会很快发展。希望这足以让你入门!