前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >thrift RPC 修改源码支持获取client ip

thrift RPC 修改源码支持获取client ip

原创
作者头像
angelo
修改2019-06-18 20:57:33
1.9K0
修改2019-06-18 20:57:33
举报
文章被收录于专栏:CDN_NewCDN_New

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

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

涉及thrift 协议:TBinaryProtocol TFramedTransport TNonblockingServerSocket

服务端核心代码:

代码语言:txt
复制
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();
        }
    }

客户端核心代码:

代码语言:txt
复制
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文件,增加一行代码:
代码语言:txt
复制
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 写入:
代码语言:txt
复制
    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();
    }
  • 接下来修改AbstractNonblockingServer.java 文件在这里将client_ip 如下修改:
代码语言:txt
复制
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();
            }下面修改thrift生成的servive 文件中增加一行代码:           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方法的参数,也可以调试根据数据流向来定位此代码。

至此我们完整实现了使thrift支持获取客户端ip。

上述更改需要首先系在thrift源码包: libthrift-0.9.3-sources.jar。修改代码后再本地编译生成jar包,在使用工程导入即可。

注:一定要注意自己使用的协议是否与文中使用的协议的相同,如果不同需要根据原理进行相应适配。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 服务端核心代码:
  • 客户端核心代码:
  • 修改
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档