我用套接字实现了一个基本的SOCKS4客户端,但我的Twisted翻译并不是很好.这是我目前的代码:
import struct
import socket
from twisted.python.failure import Failure
from twisted.internet import reactor
from twisted.internet.defer import Deferred
from twisted.internet.protocol import Protocol, ClientFactory
class Socks4Client(Protocol):
VERSION = 4
HOST = "0.0.0.0"
PORT = 80
REQUESTS = {
"CONNECT": 1,
"BIND": 2
}
RESPONSES = {
90: "request granted",
91: "request rejected or failed",
92: "request rejected because SOCKS server cannot connect to identd on the client",
93: "request rejected because the client program and identd report different user-ids"
}
def __init__(self):
self.buffer = ""
def connectionMade(self):
self.connect(self.HOST, self.PORT)
def dataReceived(self, data):
self.buffer += data
if len(self.buffer) == 8:
self.validateResponse(self.buffer)
def connect(self, host, port):
data = struct.pack("!BBH", self.VERSION, self.REQUESTS["CONNECT"], port)
data += socket.inet_aton(host)
data += "\x00"
self.transport.write(data)
def validateResponse(self, data):
version, result_code = struct.unpack("!BB", data[1:3])
if version != 4:
self.factory.protocolError(Exception("invalid version"))
elif result_code == 90:
self.factory.deferred.callback(self.responses[result_code])
elif result_code in self.RESPONSES:
self.factory.protocolError(Exception(self.responses[result_code]))
else:
self.factory.protocolError(Exception())
self.transport.abortConnection()
class Socks4Factory(ClientFactory):
protocol = Socks4Client
def __init__(self, deferred):
self.deferred = deferred
def clientConnectionFailed(self, connector, reason):
self.deferred.errback(reason)
def clientConnectionLost(self, connector, reason):
print "Connection lost:", reason
def protocolError(self, reason):
self.deferred.errback(reason)
def result(result):
print "Success:", result
def error(reason):
print "Error:", reason
if __name__ == "__main__":
d = Deferred()
d.addCallbacks(result, error)
factory = Socks4Factory(d)
reactor.connectTCP('127.0.0.1', 1080, factory)
reactor.run()
>我有一种感觉,我在滥用延迟.这是从我的客户端发送结果的正确方法吗?
>我已经阅读了一些教程,查看了文档,并阅读了与Twisted捆绑在一起的大多数协议,但我仍然无法弄清楚:ClientFactory到底是什么?我是以正确的方式使用它吗?
> clientConnectionLosts被触发了很多.有时我会失去联系并获得成功的回复.怎么会这样?这意味着什么,我应该将其视为错误吗?
>如何确保我的延迟调用只有一个回调/错误回复?
任何提示都表示赞赏.
解决方法:
I have a feeling that I’m abusing Deferred. Is this the right way to send results from my client?
它并不理想,但它也不是完全错误的.通常,您应该尝试将实例化Deferred的代码保持尽可能接近在Deferred上调用Deferred.callback或Deferred.errback的代码.在这种情况下,这些代码段相距很远 – 前者位于__main__中,而后者位于由__main__中的代码创建的类创建的类中.这有点像Demeter法则 – 这两件事之间的步骤越多,软件的耦合越紧密,越不灵活,越脆弱.
考虑为Socks4Client提供一个创建并返回此Deferred实例的方法.然后,尝试使用端点设置连接,以便您可以更轻松地调用此方法:
endpoint = TCP4StreamClientEndpoint(reactor, "127.0.0.1", 1080)
d = endpoint.connect(factory)
def connected(protocol):
return protocol.waitForWhatever()
d.addCallback(connected)
d.addCallbacks(result, error)
这里需要注意的一点是使用端点,不会调用工厂的clientConnectionFailed和clientConnectionLost方法.端点接管前者(尽管不是后者).
I’ve read a few tutorials, looked at the documentation, and read through most of the protocols bundled with Twisted, but I still can’t figure it out: what exactly is a ClientFactory for? Am I using it the right way?
这就是你正在做的事情. :)它创建用于连接的协议实例.需要工厂,因为您可能会创建与许多服务器(或与一个服务器的多个连接)的连接.但是,很多人在使用ClientFactory时遇到了麻烦,因此最近推出的Twisted API并不依赖于它.例如,您还可以将连接设置为:
endpoint = TCP4StreamClientEndpoint(reactor, "127.0.0.1", 1080)
d = connectProtocol(endpoint, Socks4Client())
...
ClientFactory现在已经不在了.
clientConnectionLosts gets triggered a lot. Sometimes I lose the connection and get a successful response. How is that so? What does this mean, and should I treat it as an error?
每个连接最终都必须丢失.您必须自己决定这是否是错误.如果你已经完成了你想要做的所有事情并且你调用了lostConnection,那么这可能不是一个错误.考虑与HTTP服务器的连接.如果您已发送请求并收到回复,则丢失连接可能不是什么大问题.但如果你只收到一半的回复,那就是问题所在.
How do I make sure that my deferred calls only one callback/errback?
如果您按照上面第一个问题的描述构建代码,那么执行此操作会变得更容易.当在Deferred上使用回调/错误的代码分散在程序的大部分内容时,那么正确地执行此操作变得更加困难.
不过,这只是适当的状态跟踪问题.一旦你推迟了结果,你必须安排知道你不应该给它另一个.一个常见的习惯用法是删除对Deferred的引用.例如,如果要将其保存为协议实例上的属性值,则在给出Deferred其结果时将该属性设置为None.