簡體   English   中英

如何在python thrift服務器中獲取客戶端的IP

[英]How to get client's IP in a python thrift server

我在python中編寫了一個thrift服務,我想了解如何在處理函數上下文中獲取客戶端的IP地址。

謝謝,親愛。

您需要獲取傳輸,並從那里獲取數據。 不確定如何在Python中完全執行此操作,但是有一個郵件列表線程,並且有這個JIRA票證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);
  }  
}

這有點舊,但我目前正在解決同樣的問題。 這是我的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進行調用

這是相同的包裝器,翻譯成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);
    }
}

我發現在服務處理程序中獲取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映射可能看起來多余,但它不是因為沒有辦法獲得處理器的處理程序(即沒有getter)。

請注意,您的ServiceHandler實例需要保留與之關聯的套接字。 在這里我將它傳遞給構造函數,但任何方式都可以。 然后,當調用ServiceHandlerIFace實現時,它將已經具有關聯的Socket。

這也意味着你將為每個連接的客戶端提供一個MyProcessorServiceHandler實例,我認為不是基本Thrift的情況,其中每個類只創建一個實例。

這個解決方案也有一個非常惱人的缺點:你需要找出一種從PROCESSORSHANDLERS映射中刪除過時數據的方法,否則這些映射將無限增長。 在我的情況下,每個客戶端都有一個唯一的ID,因此我可以檢查該客戶端是否有過時的套接字並將其從映射中刪除。

PS:Thrift人需要找到一種讓服務處理程序獲取當前調用的已使用協議的方法(例如,允許擴展基類而不是實現接口)。 這在很多場景中非常有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM