关闭

thrift 获取客户端client ip TBinaryProtocol TFramedTransport TNonblockingServerSocket

标签: thrift客户端ipTBinaryProtocolTFramedTransportTNonblockingServerSo
1208人阅读 评论(1) 收藏 举报

使用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



   
2
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1892次
    • 积分:41
    • 等级:
    • 排名:千里之外
    • 原创:2篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章存档
    最新评论