我正在python中编写一个thrift服务,我想了解我的能力 在处理程序函数上下文中获取客户端的IP地址。
谢谢, 爱。
答案 0 :(得分:0)
您需要获取传输,并从那里获取数据。不确定如何在Python中完全做到这一点,但有一个mailing list thread和this 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。
这也意味着每个连接的客户端都会有一个IFace
和MyProcessor
的实例,我认为不是基本Thrift的情况,每个类只创建一个实例。
此解决方案还有一个非常恼人的缺点:您需要找出一种方法来从ServiceHandler
和PROCESSORS
地图中删除过时的数据,否则这些地图将无限增长。在我的情况下,每个客户端都有一个唯一的ID,所以我可以检查这个客户端是否有过时的套接字,并从地图中删除它们。