如何在python thrift服务器中获取客户端的IP

时间:2013-12-25 16:28:03

标签: python thrift

我正在python中编写一个thrift服务,我想了解我的能力 在处理程序函数上下文中获取客户端的IP地址。

谢谢, 爱。

4 个答案:

答案 0 :(得分:0)

您需要获取传输,并从那里获取数据。不确定如何在Python中完全做到这一点,但有一个mailing list threadthis JIRA-ticket THRIFT-1053描述了C ++ / Java的解决方案。

这是邮件列表主题的相关部分:

  

我是通过装饰像这个伪代码的TProcessor那样做的。

     

-craig

class TrackingProcessor implements TProcessor {
 TrackingProcessor (TProcessor processor) {this.processor=processor;}

 public boolean process(TProtocol in, TProtocol out) throws TException {
   TTransport t = in.getTransport();
   InetAddress ia = t instanceof TSocket ?
       ((TSocket)t).getSocket().getInetAddress() : null;
   // Now you have the IP address, so what ever you want.

   // Delegate to the processor we are decorating.
   return processor.process(in,out);
  }  
}

答案 1 :(得分:0)

这有点旧,但我目前正在解决同样的问题。 这是我对thriftpy的解决方案:

import thriftpy
from thriftpy.thrift import TProcessor, TApplicationException, TType
from thriftpy.server import TThreadedServer
from thriftpy.protocol import TBinaryProtocolFactory
from thriftpy.transport import TBufferedTransportFactory, TServerSocket

class CustomTProcessor(TProcessor):
    def process_in(self, iprot):
        api, type, seqid = iprot.read_message_begin()
        if api not in self._service.thrift_services:
            iprot.skip(TType.STRUCT)
            iprot.read_message_end()
            return api, 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] for k in sorted(args.thrift_spec)]

        # get client IP address
        client_ip, client_port = iprot.trans.sock.getpeername()

        def call():
            f = getattr(self._handler, api)
            return f(*(args.__dict__[k] for k in api_args), client_ip=client_ip)

        return api, seqid, result, call

class PingPongDispatcher:
    def ping(self, param1, param2, client_ip):
        return "pong %s" % client_ip

pingpong_thrift = thriftpy.load("pingpong.thrift")
processor = CustomTProcessor(pingpong_thrift.PingService, PingPongDispatcher())
server_socket = TServerSocket(host="127.0.0.1", port=12345, client_timeout=10000)
server = TThreadedServer(processor,
                         server_socket,
                         iprot_factory=TBinaryProtocolFactory(),
                         itrans_factory=TBufferedTransportFactory())
server.serve()

请记住,调度程序中的每个方法都将使用额外的参数client_ip

进行调用

答案 2 :(得分:-1)

这是相同的包装器,翻译成C#。这个答案只是谷歌搜索这个问题的唯一好结果,所以我认为其他人可能更容易将它翻译成他们选择的语言给定两个参考点而不是一个。为了记录,这对我来说非常适合。

(注意“in”和“out”是C#中的保留字)

using Thrift;
using System.Net;

class TrackingProcessor : TProcessor
{
    private TProcessor processor;
    public TrackingProcessor(TProcessor processor)
    {
        this.processor = processor;
    }

    public Boolean Process(TProtocol inProt, TProtocol outProt)
    {
        TTransport t = inProt.Transport;
        IPAddress ip = ((IPEndPoint)((TSocket)t).TcpClient.Client.RemoteEndPoint).Address;
        //Presumably we want to do something with this IP
        return processor.Process(inProt, outProt);
    }
}

答案 3 :(得分:-1)

我发现在服务处理程序中获取TProtocol的唯一方法是扩展处理器并为每个与传输/协议相关的客户端创建一个处理程序实例。这是一个例子:

public class MyProcessor implements TProcessor {

    // Maps sockets to processors
    private static final Map<, Processor<ServiceHandler>> PROCESSORS = Collections.synchronizedMap(new HashMap<String, Service.Processor<ServiceHandler>>());

    // Maps sockets to handlers
    private static final Map<String, ServiceHandler> HANDLERS = Collections.synchronizedMap(new HashMap<String, ServiceHandler>());

    @Override
    public boolean process(final TProtocol in, final TProtocol out)
            throws TException {

        // Get the socket for this request
        final TTransport t = in.getTransport();
        // Note that this cast will fail if the transport is not a socket, so you might want to add some checking.
        final TSocket socket = (TSocket) t; 

        // Get existing processor for this socket if any
        Processor<ServiceHandler> processor = PROCESSORS.get(socket);
        // If there's no processor, create a processor and a handler for
        // this client and link them to this new socket
        if (processor == null) {
            // Inform the handler of its socket
            final ServiceHandler handler = new ServiceHandler(socket);
            processor = new Processor<ServiceHandler>(handler);
            PROCESSORS.put(clientRemote, processor);
            HANDLERS.put(clientRemote, handler);
        }
        return processor.process(in, out);
    }
}

然后你需要告诉Thrift将此处理器用于传入请求。对于TThreadPoolServer,它是这样的:

final TThreadPoolServer.Args args = new TThreadPoolServer.Args(new TServerSocket(port));
args.processor(new MyProcessor());
final TThreadPoolServer server = new TThreadPoolServer(args);

PROCESSORS地图可能看起来多余,但不是因为没有办法获得处理器的处理程序(即没有吸气剂)。

请注意,您的ServiceHandler实例需要保留与之关联的套接字。在这里我将它传递给构造函数,但任何方式都可以。然后,当调用ServiceHandler的{​​{1}}实现时,它将具有相关的Socket。

这也意味着每个连接的客户端都会有一个IFaceMyProcessor的实例,我认为不是基本Thrift的情况,每个类只创建一个实例。

此解决方案还有一个非常恼人的缺点:您需要找出一种方法来从ServiceHandlerPROCESSORS地图中删除过时的数据,否则这些地图将无限增长。在我的情况下,每个客户端都有一个唯一的ID,所以我可以检查这个客户端是否有过时的套接字,并从地图中删除它们。

PS:Thrift人需要想办法让服务处理程序获取当前调用的已使用协议(例如,允许扩展基类而不是实现接口)。这在很多场景中非常有用。