thrift server端获取客户端ip python
真是费了我九牛二虎之力,终于搞定
网上有说如下方式获取的
classCustomTProcessor(TProcessor):
defprocess_in(self,
iprot):
api, type, seqid = iprot.read_message_begin()
ifapi
not inself._service.thrift_services:
iprot.skip(TType.STRUCT)
iprot.read_message_end()
returnapi, seqid, TApplicationException(TApplicationException.UNKNOWN_METHOD),None
# noqa
args =getattr(self._service,
api +"_args")()
args.read(iprot)
iprot.read_message_end()
result =getattr(self._service,
api +"_result")()
# convert kwargs to args
api_args = [args.thrift_spec[k][1]fork
insorted(args.thrift_spec)]
# get client IP address
client_ip, client_port = iprot.trans.sock.getpeername()
defcall():
f =getattr(self._handler, api)
returnf(*(args.__dict__[k]fork
inapi_args),
client_ip=client_ip)
return api, seqid, result,call
关键就在于
iprot.trans.sock.getpeername()
但实测不行,应该是我的版本原因吧
根据这个思路,应该要在processor = ProducerService.Processor(personServiceHandler)
此处获取
1.classProcessor(Iface, TProcessor):
def__init__(self,
handler):
self._handler = handler
self._processMap = {}
self._processMap["sendSync"]
= Processor.process_sendSync
self._processMap["sendAsync"]
= Processor.process_sendAsync
defprocess(self, iprot, oprot):
(name, type, seqid) = iprot.readMessageBegin()
print str(iprot.trans)
此处加断点调试,看iprot是啥
trans下面
有socket,是否这样就可以打出来呢
把iprot.trans._TFramedTransport__trans打印,发现服务端报错(实际可能是我少打了一个下划线,所以服务端报错了,被自己坑了)
thrift 服务端报错很不友好,不会报具体位置,只是打印有问题。
然后想,这里不能打,thrift是基于tcp的连接,肯定是socket连接,就一定有对方的ip,port,
我们知道socket连接建立,服务端是指accept这一步拿到新的fd,即新的socket,那就到这一步来找
2.通过单步调试,可以看到是在这一步accept的
classTSimpleServer(TServer):
"""Simple single-threaded server that just pumps around one transport."""
def__init__(self,
*args):
TServer.__init__(self,
*args)
defserve(self):
self.serverTransport.listen()
whileTrue:
client =self.serverTransport.accept()
if notclient:
continue
itrans =self.inputTransportFactory.getTransport(client)
otrans =self.outputTransportFactory.getTransport(client)
iprot =self.inputProtocolFactory.getProtocol(itrans)
oprot =self.outputProtocolFactory.getProtocol(otrans)
try:
whileTrue:
self.processor.process(iprot, oprot)
exceptTTransport.TTransportException
as
tx:
pass
exceptExceptionas
x:
logger.exception(x)
itrans.close()
otrans.close()
这时候可以看到client就是个socket的实例。
根据之前的经验,thrift的socket获取还需要加handle,所以此处加入打印
printclient.handle.getpeername(),client.host
再调试,发现轻松打印出来了对方ip port和自己的
('10.94.96.140', 43046) localhost
3.实现
知道在哪可以拿到了,那么就想办法取了,
首先重新写一个server
classabServer(TServer.TSimpleServer):
defserve(self):
self.serverTransport.listen()
whileTrue:
client =self.serverTransport.accept()
if notclient:
continue
itrans =self.inputTransportFactory.getTransport(client)
otrans =self.outputTransportFactory.getTransport(client)
iprot =self.inputProtocolFactory.getProtocol(itrans)
oprot =self.outputProtocolFactory.getProtocol(otrans)
try:
whileTrue:
self.processor.process(iprot, oprot,client)
exceptTTransport.TTransportException
as
tx:
pass
exceptExceptionas
x:
logger.exception(x)
itrans.close()
otrans.close()
目的是把client传递下去
然后重写process函数
classProcessor(Iface, TProcessor):
def__init__(self,
handler):
self._handler = handler
self._processMap = {}
self._processMap["sendSync"]
= Processor.process_sendSync
self._processMap["sendAsync"]
= Processor.process_sendAsync
defprocess(self,
iprot, oprot,client):
(name, type, seqid) = iprot.readMessageBegin()
printclient.handle.getpeername(),client.host
if namenot inself._processMap:
这样就可以用了
('10.94.96.140', 43046)
这就更好了,可以把原理加的参数传递去掉,不用改太底层了。
5.总结,底层原理懂了,知道在哪一步肯定能拿到,再反推看看尽量不改的情况下拿到。