thrift 获取客户端client ip TBinaryProtocol TFramedTransport TNonblockingServerSocket

原创 2016年08月31日 15:40:07

使用thrift做项目的时候,用到了thrift框架,后来遇到一个很棘手的问题,就是在使用TBinaryProtocol TFramedTransport TNonblockingServerSocket等协议时,服务器端无法得到client的ip地址。

经过了几天的研究,发现如下方法可以极简(三行)更改代码的同时,解决获取ip的问题。


服务器代码:

public static void main(String[] args) {
        try {
            TNonblockingServerSocket socket = new TNonblockingServerSocket(PORT);
            TProcessor processor = new KkLog.Processor(new KkServiceImpl());
            TThreadedSelectorServer.Args arg = new TThreadedSelectorServer.Args(socket);

            arg.transportFactory(new TFramedTransport.Factory());
            arg.protocolFactory(new TBinaryProtocol.Factory());

            arg.processorFactory(new TProcessorFactory(processor));
            TServer server = new TThreadedSelectorServer(arg);

            server.serve();

        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



客户端代码:

public static void main(String[] args) {
        if(args.length<1){
            System.out.println("run as java -jar KkClient.jar serverIP");
            return ;
        }
        TTransport transport = new TFramedTransport(new TSocket(IP, PORT, clientTimeout));
        TProtocol protocol = new TBinaryProtocol(transport);
        KkLog.Client client = new KkLog.Client(protocol);

        try {
            transport.open();

            
            client.sendLog("0.0.0.0", data); //这里客户端调用sendLog发送data,前面是ip地址,由服务器接收到后填充。

        } catch (TApplicationException e) { // 异常的文档 http://people.apache.org/~thejas/thrift-0.9/javadoc/org/apache/thrift/TException.html
            System.out.println(e.getMessage() + " " + e.getType());
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        transport.close();
    }



从maven下载了thrift-0.9.3版本的源码,修改地方如下:

修改org.apache.thrift.protocol.TBinaryProtocol.java文件,增加一行代码:public String client_ip="0.0.0.0";

思想是将获取到ip后,将ip保存到client_ip中,需要用到时再提取即可。
package org.apache.thrift.protocol;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

import org.apache.thrift.TException;
import org.apache.thrift.transport.TTransport;

/**
 * Binary protocol implementation for thrift.
 * Customized by tongange@haizhi.com 20160830
 */
public class TBinaryProtocol extends TProtocol {
  private static final TStruct ANONYMOUS_STRUCT = new TStruct();
  private static final long NO_LENGTH_LIMIT = -1;

  protected static final int VERSION_MASK = 0xffff0000;
  protected static final int VERSION_1 = 0x80010000;

    public String client_ip="0.0.0.0";  //《《《《《《《《《《—————————在这里增加

  /**
   * The maximum number of bytes to read from the transport for
   * variable-length fields (such as strings or binary) or {@link #NO_LENGTH_LIMIT} for
   * unlimited.
   */
  private final long stringLengthLimit_;



接下来修改AbstractNonblockingServer.java 文件在这里将client_ip 写入:一行代码

public void invoke() {
      frameTrans_.reset(buffer_.array());
      response_.reset();
      
      try {
        if (eventHandler_ != null) {
          eventHandler_.processContext(context_, inTrans_, outTrans_);
        }
        //下面这行是从TNonblockingSocket中获取socketChannel进而获取client 的ip。并保存到inProt_的新加字段中。下面的强制转换根据自己实际用到的协议实际填写。((TBinaryProtocol)inProt_).client_ip=((InetSocketAddress)((TNonblockingSocket)this.trans_).getSocketChannel().getRemoteAddress()).getAddress().getHostAddress();
        processorFactory_.getProcessor(inTrans_).process(inProt_, outProt_);
        responseReady();
        return;
      } catch (TException te) {
        LOGGER.warn("Exception while invoking!", te);
      } catch (Throwable t) {
        LOGGER.error("Unexpected throwable while invoking!", t);
      }
      // This will only be reached when there is a throwable.
      state_ = FrameBufferState.AWAITING_CLOSE;
      requestSelectInterestChange();
    }
这样,我们就将client的ip保存下来。


下面修改thrift生成的servive 文件中增加一行代码:

private static class sendLog_argsStandardScheme extends StandardScheme<sendLog_args> {

            public void read(org.apache.thrift.protocol.TProtocol iprot, sendLog_args struct) throws org.apache.thrift.TException {
                org.apache.thrift.protocol.TField schemeField;
                iprot.readStructBegin();
                while (true)
                {
                    schemeField = iprot.readFieldBegin();
                    if (schemeField.type == org.apache.thrift.protocol.TType.STOP) {
                        break;
                    }
                    switch (schemeField.id) {
                        case 1: // IP
                            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
                                struct.ip = iprot.readString();
				struct.ip = ((TBinaryProtocol)iprot).client_ip;   //在这里添加使用我们保存的ip覆盖客户端传来的。
//因为客户端无法获得自己的ip,所以客户端发来什么都无所谓,保留接口在服务器端填充就行。

                                struct.setTypeIsSet(true);
                            } else {
                                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
                            }
                            break;
                        case 2: // LOG
                            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
                                struct.log = iprot.readString();
                                struct.setLogIsSet(true);
                            } else {
                                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
                            }
                            break;
                        default:
                            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
                    }
                    iprot.readFieldEnd();
                }
                iprot.readStructEnd();

                // check for required fields of primitive type, which can't be checked in the validate method
                struct.validate();
            }

            public void write(org.apache.thrift.protocol.TProtocol oprot, sendLog_args struct) throws org.apache.thrift.TException {
                struct.validate();

                oprot.writeStructBegin(STRUCT_DESC);
                if (struct.type != null) {
                    oprot.writeFieldBegin(TYPE_FIELD_DESC);
                    oprot.writeString(struct.type);
                    oprot.writeFieldEnd();
                }
                if (struct.log != null) {
                    oprot.writeFieldBegin(LOG_FIELD_DESC);
                    oprot.writeString(struct.log);
                    oprot.writeFieldEnd();
                }
                oprot.writeFieldStop();
                oprot.writeStructEnd();
            }

        }
生文件是执行 thrift --gen java **.thrift之后生成的,sendLog_args是sendLog方法的参数,也可以调试根据数据流向来定位此代码。
这样我们将client_ip取出来就完成了。


上述更改需要首先系在thrift源码包: libthrift-0.9.3-sources.jar。修改代码后再本地编译生成jar包,在使用工程导入即可。
注:一定要注意自己使用的协议是否和我的相同,如果不同需要相应修改。
欢迎转载,请注明出处。http://blog.csdn.net/ttttaaaagggg/article/details/52385750



                    

相关文章推荐

Thrift源码分析(六)-- Transport传输层分析

RPC作为一种特殊的网络编程,会封装一层传输层来支持底层的网络通信。Thrift使用了Transport来封装传输层,但Transport不仅仅是底层网络传输,它还是上层流的封装。 关于Transp...
  • ITer_ZC
  • ITer_ZC
  • 2014年09月30日 13:58
  • 4662

thrift源码研究-transport类体系研究总结

transport类体系架构与TProtocol类体系架构一样,所以这里就不重复叙述了,想了解可转去TProtocol类体系架构分析那篇。  下面将对transport层的几种transport类进行...
  • whycold
  • whycold
  • 2013年01月23日 21:54
  • 6953

Thrift源码分析(五)-- FrameBuffer类分析

FrameBuffer是Thrift NIO服务器端的一个核心组件,它一方面承担了NIO编程中的缓冲区的功能,另一方面还承担了RPC方法调用的职责。 FrameBufferSta...
  • ITer_ZC
  • ITer_ZC
  • 2014年09月30日 11:34
  • 4867

由浅入深了解Thrift(一)——Thrift介绍与用法

一、  Thrift简单介绍 1.1、  Thrift是什么?能做什么? Thrift是Facebook于2007年开发的跨语言的rpc服框架,提供多语言的编译功能,并提供多种服务器工作模式;用户通过...
  • hjx_1000
  • hjx_1000
  • 2015年01月16日 16:27
  • 14422

Thrift结构分析及增加取客户端IP功能实现

目录 目录 1 1. 前言 1 2. 示例Service 1 3. 网络部分类图 2 4. 线程模式 3 4.1. IO线程 3 4.2. 工作线程 4 4.2.1. 工作线程类图...

Thrift in python<转>

Thrift官网上的文档很少,从网上搜到的也大都千篇一律,即使是《Thrift: the missing guide》对如何构建python的server和client也没有进行详尽讲述。本博特意看了...

两种方式获取Thrift调用的客户端IP地址

thrift依赖 org.apache.thrift libthrift 0.9.3 方法一: package com.lala.server; imp...
  • mn960mn
  • mn960mn
  • 2016年01月26日 09:46
  • 3796

Thrift 各种服务端和客户端实现

//简单的单线程服务模型 import org.apache.thrift.TException; import org.apache.thrift.TProcessor; import org.a...

Thrift初学--服务端构造(阻塞、非阻塞方式两种服务端)

Thrift服务器的创建,常规分为阻塞、非阻塞模式。 可以从源码上看出其缘由!...

Thrift源码分析(七)-- TServer服务器分析

Thrift采用了TServer来作为服务器的抽象,提供了多种类型的服务器实现。用TServerTransport作为服务器的Acceptor抽象,来监听端口,创建客户端Socket连接 先来看...
  • ITer_ZC
  • ITer_ZC
  • 2014年09月30日 16:20
  • 4072
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:thrift 获取客户端client ip TBinaryProtocol TFramedTransport TNonblockingServerSocket
举报原因:
原因补充:

(最多只允许输入30个字)