TTransport

    TTransport负责数据的传输,先看类结构图。

      

    阻塞Server使用TServerSocket,它封装了ServerSocket实例,ServerSocket实例监听到客户端的请求会创建一个Socket对象,并将该Socket对象封装为一个TSocket对象用于通信。

    非阻塞Server使用TNonblockingServerSocket,它封装了一个ServerSocketChannel实例,ServerSocketChannel实例监听到客户端的请求会创建一个SocketChannel对象,并将该对象封装成一个TNonblockingSocket对象用于之后的通信。当读取完客户端的请求数据后,保存为本地的一个TTransport对象,然后封装为TFramedTransport对象进行处理。

    TTransport

      TTransport是客户端所有Transport的基类。

public abstract class TTransport {
public abstract boolean isOpen();//transport是否打开
public boolean peek() {//是否还有数据要读,如果transport打开时还有数据要读
return isOpen();
}
public abstract void open() throws TTransportException;//打开transport读写数据
public abstract void close();//关闭transport
//读取len长度的数据到字节数组buf,off表示开始读的位置,返回实际读取的字节数(不一定为len)
public abstract int read(byte[] buf, int off, int len) throws TTransportException;
//确保读取len长度的数据到字节数组buf,off表示开始读的位置,通过循环调用read()实现,返回实际读取的字节数(len)
public int readAll(byte[] buf, int off, int len)
throws TTransportException {
int got = 0;
int ret = 0;
while (got < len) {
ret = read(buf, off+got, len-got);
if (ret <= 0) {
throw new TTransportException(
"Cannot read. Remote side has closed. Tried to read "
+ len
+ " bytes, but only got "
+ got
+ " bytes. (This is often indicative of an internal error on the server side. Please check your server logs.)");
}
got += ret;
}
return got;
}
//将buf中的全部数据写到output
public void write(byte[] buf) throws TTransportException {
write(buf, 0, buf.length);
}
//将buf中off位置开始len长度的数据写到output
public abstract void write(byte[] buf, int off, int len) throws TTransportException;
//清空transport缓存中的数据
public void flush() throws TTransportException {}
//获取本地缓存的数据,没有则返回null
public byte[] getBuffer() {
return null;
}
//获取本地缓存的下一个读取位置,没有则返回0
public int getBufferPosition() {
return 0;
}
//获取本地缓存的字节数,没有则返回-1
public int getBytesRemainingInBuffer() {
return -1;
}
//从本地缓存中消费n个字节
public void consumeBuffer(int len) {}
}

    TIOStreamTransport

      TIOStreamTransport是面向流的TTransport的子类,阻塞式,实现了流的操作。

public class TIOStreamTransport extends TTransport {
private static final Logger LOGGER = LoggerFactory.getLogger(TIOStreamTransport.class.getName());
protected InputStream inputStream_ = null;//输入流
protected OutputStream outputStream_ = null;//输出流
//一波构造函数
protected TIOStreamTransport() {}
public TIOStreamTransport(InputStream is) {
inputStream_ = is;
}
public TIOStreamTransport(OutputStream os) {
outputStream_ = os;
}
public TIOStreamTransport(InputStream is, OutputStream os) {
inputStream_ = is;
outputStream_ = os;
}
//streams必须在构造时已经被打开,so一直返回true
public boolean isOpen() {
return true;
}
//streams必须在构造时已经被打开,不需要这个方法
public void open() throws TTransportException {}
//关闭流
public void close() {
if (inputStream_ != null) {
try {
inputStream_.close();
} catch (IOException iox) {
LOGGER.warn("Error closing input stream.", iox);
}
inputStream_ = null;
}
if (outputStream_ != null) {
try {
outputStream_.close();
} catch (IOException iox) {
LOGGER.warn("Error closing output stream.", iox);
}
outputStream_ = null;
}
}
//将输入流中的指定数据读取到buf中
public int read(byte[] buf, int off, int len) throws TTransportException {
if (inputStream_ == null) {
throw new TTransportException(TTransportException.NOT_OPEN, "Cannot read from null inputStream");
}
int bytesRead;
try {
bytesRead = inputStream_.read(buf, off, len);
} catch (IOException iox) {
throw new TTransportException(TTransportException.UNKNOWN, iox);
}
if (bytesRead < 0) {
throw new TTransportException(TTransportException.END_OF_FILE);
}
return bytesRead;
}
//将buf中的数据写出的输出流outputStream_
public void write(byte[] buf, int off, int len) throws TTransportException {
if (outputStream_ == null) {
throw new TTransportException(TTransportException.NOT_OPEN, "Cannot write to null outputStream");
}
try {
outputStream_.write(buf, off, len);
} catch (IOException iox) {
throw new TTransportException(TTransportException.UNKNOWN, iox);
}
}
//清空输出流
public void flush() throws TTransportException {
if (outputStream_ == null) {
throw new TTransportException(TTransportException.NOT_OPEN, "Cannot flush null outputStream");
}
try {
outputStream_.flush();
} catch (IOException iox) {
throw new TTransportException(TTransportException.UNKNOWN, iox);
}
}
}

    TSocket

      TSocket类继承自TIOStreamTransport类,实现了对Socket实例的包装。inputStream_和outputStream_通过Socket初始化。

public class TSocket extends TIOStreamTransport {
private static final Logger LOGGER = LoggerFactory.getLogger(TSocket.class.getName());
private Socket socket_ = null;//包装socket_
private String host_ = null;//远程host
private int port_ = 0;//远程port
private int timeout_ = 0;//Socket超时时间
//三个构造函数
public TSocket(Socket socket) throws TTransportException {
socket_ = socket;
try {
socket_.setSoLinger(false, 0);
socket_.setTcpNoDelay(true);
} catch (SocketException sx) {
LOGGER.warn("Could not configure socket.", sx);
} if (isOpen()) {
try {
//初始化inputStream_和outputStream_
inputStream_ = new BufferedInputStream(socket_.getInputStream(), 1024);
outputStream_ = new BufferedOutputStream(socket_.getOutputStream(), 1024);
} catch (IOException iox) {
close();
throw new TTransportException(TTransportException.NOT_OPEN, iox);
}
}
}
public TSocket(String host, int port) {
this(host, port, 0);
}
public TSocket(String host, int port, int timeout) {
host_ = host;
port_ = port;
timeout_ = timeout;
initSocket();
}
//初始化Socket
private void initSocket() {
socket_ = new Socket();
try {
socket_.setSoLinger(false, 0);
socket_.setTcpNoDelay(true);
socket_.setSoTimeout(timeout_);
} catch (SocketException sx) {
LOGGER.error("Could not configure socket.", sx);
}
}
public void setTimeout(int timeout) {
timeout_ = timeout;
try {
socket_.setSoTimeout(timeout);
} catch (SocketException sx) {
LOGGER.warn("Could not set socket timeout.", sx);
}
}
public Socket getSocket() {
if (socket_ == null) {
initSocket();
}
return socket_;
}
//检查socket_是否连接
public boolean isOpen() {
if (socket_ == null) {
return false;
}
return socket_.isConnected();
}
//打开socket连接,初始化输入流和输出流
public void open() throws TTransportException {
if (isOpen()) {
throw new TTransportException(TTransportException.ALREADY_OPEN, "Socket already connected.");
}
if (host_.length() == 0) {
throw new TTransportException(TTransportException.NOT_OPEN, "Cannot open null host.");
}
if (port_ <= 0) {
throw new TTransportException(TTransportException.NOT_OPEN, "Cannot open without port.");
}
if (socket_ == null) {
initSocket();
}
try {
socket_.connect(new InetSocketAddress(host_, port_), timeout_);
inputStream_ = new BufferedInputStream(socket_.getInputStream(), 1024);
outputStream_ = new BufferedOutputStream(socket_.getOutputStream(), 1024);
} catch (IOException iox) {
close();
throw new TTransportException(TTransportException.NOT_OPEN, iox);
}
}
//关闭socket
public void close() {
super.close();
if (socket_ != null) {
try {
socket_.close();
} catch (IOException iox) {
LOGGER.warn("Could not close socket.", iox);
}
socket_ = null;
}
}
}

    TFramedTransport

      TFramedTransport作用是通过message之前的4-byte frame size确保读到的message时完整的,防止发生粘包拆包的问题。

//TFramedTransport作用是通过message之前的4-byte frame size确保读到的message时完整的,防止发生粘包拆包的问题
public class TFramedTransport extends TTransport {
protected static final int DEFAULT_MAX_LENGTH = 16384000;//默认的本地缓存最大字节数
private int maxLength_;//本地缓存最大字节数
private TTransport transport_ = null;//封装的transport_,实际通过该对象实现数据的读取与写入
private final TByteArrayOutputStream writeBuffer_ = new TByteArrayOutputStream(1024);//输出BUffer,将字节数组输出
private TMemoryInputTransport readBuffer_ = new TMemoryInputTransport(new byte[0]);//输入buffer,用于数据读取
//工厂类,用于将一个TTransport实例封装为TFramedTransport实例
public static class Factory extends TTransportFactory {
private int maxLength_;
public Factory() {
maxLength_ = TFramedTransport.DEFAULT_MAX_LENGTH;
}
public Factory(int maxLength) {
maxLength_ = maxLength;
}
@Override
public TTransport getTransport(TTransport base) {
return new TFramedTransport(base, maxLength_);
}
}
//两个构造函数
public TFramedTransport(TTransport transport, int maxLength) {
transport_ = transport;
maxLength_ = maxLength;
}
public TFramedTransport(TTransport transport) {
transport_ = transport;
maxLength_ = TFramedTransport.DEFAULT_MAX_LENGTH;
}
//同transport_的三个方法
public void open() throws TTransportException {
transport_.open();
}
public boolean isOpen() {
return transport_.isOpen();
}
public void close() {
transport_.close();
}
//读数据,一次请求可能调用多次
public int read(byte[] buf, int off, int len) throws TTransportException {
if (readBuffer_ != null) {
//在一次客户端的请求中第一次调用该方法时,肯定返回got<0,就可以进入 readFrame()方法。
int got = readBuffer_.read(buf, off, len);//readBuffer_已读完或字节数为0时 肯定返回got<0
if (got > 0) {
return got;
}
}
readFrame();//从transport_读到本地缓存readBuffer_
return readBuffer_.read(buf, off, len);
}
@Override
public byte[] getBuffer() {
return readBuffer_.getBuffer();
}
@Override
public int getBufferPosition() {
return readBuffer_.getBufferPosition();
}
@Override
public int getBytesRemainingInBuffer() {
return readBuffer_.getBytesRemainingInBuffer();
}
@Override
public void consumeBuffer(int len) {
readBuffer_.consumeBuffer(len);
} private final byte[] i32buf = new byte[4]; private void readFrame() throws TTransportException {
transport_.readAll(i32buf, 0, 4); //读前4个字节,FrameSize
int size = decodeFrameSize(i32buf);//由于发送数据方对FrameSize进行了编码,通过解码得到消息的大小
//校验FrameSize是否正确
if (size < 0) {
throw new TTransportException("Read a negative frame size (" + size + ")!");
}
if (size > maxLength_) {
throw new TTransportException("Frame size (" + size + ") larger than max length (" + maxLength_ + ")!");
}
byte[] buff = new byte[size];
transport_.readAll(buff, 0, size);//将FrameSize大小的全部数据读到buff
readBuffer_.reset(buff);//重置本地缓存
}
//write是向本地缓存写入数据,写完后,所有的调用方都要对输出流调用flush进行清空,所以下面一定会进入到flush方法,再通过transport_将本地缓存的数据写出去
public void write(byte[] buf, int off, int len) throws TTransportException {
writeBuffer_.write(buf, off, len);
}
@Override
public void flush() throws TTransportException {
byte[] buf = writeBuffer_.get();
int len = writeBuffer_.len();
writeBuffer_.reset();//清空
encodeFrameSize(len, i32buf);//对FrameSize进行编码
transport_.write(i32buf, 0, 4);//先写数据大小FrameSize
transport_.write(buf, 0, len);//在写真实数据
transport_.flush();//清空
}
//以下两个方法是对FrameSize进行编解码,将每个字节高位都位移到低位组成byte数组
public static final void encodeFrameSize(final int frameSize, final byte[] buf) {
buf[0] = (byte)(0xff & (frameSize >> 24));
buf[1] = (byte)(0xff & (frameSize >> 16));
buf[2] = (byte)(0xff & (frameSize >> 8));
buf[3] = (byte)(0xff & (frameSize));
}
public static final int decodeFrameSize(final byte[] buf) {
return
((buf[0] & 0xff) << 24) |
((buf[1] & 0xff) << 16) |
((buf[2] & 0xff) << 8) |
((buf[3] & 0xff));
}
}

      TFramedTransport用到了TMemoryInputTransport类,TMemoryInputTransport封装了一个字节数组byte[]来做输入流的封装。

public final class TMemoryInputTransport extends TTransport {
private byte[] buf_;//保存数据的字节数组
private int pos_;//可读数据的开始位置
private int endPos_;//可读数据的的结束位置
public TMemoryInputTransport() {
}
public TMemoryInputTransport(byte[] buf) {
reset(buf);
}
public TMemoryInputTransport(byte[] buf, int offset, int length) {
reset(buf, offset, length);
}
//重置buf
public void reset(byte[] buf) {
reset(buf, 0, buf.length);
}
public void reset(byte[] buf, int offset, int length) {
buf_ = buf;
pos_ = offset;
endPos_ = offset + length;
}
public void clear() {
buf_ = null;
}
@Override
public void close() {}
@Override
public boolean isOpen() {
return true;
}
@Override
public void open() throws TTransportException {}
@Override
public int read(byte[] buf, int off, int len) throws TTransportException {
int bytesRemaining = getBytesRemainingInBuffer();//获取剩余可读的数据大小
int amtToRead = (len > bytesRemaining ? bytesRemaining : len);
if (amtToRead > 0) {
System.arraycopy(buf_, pos_, buf, off, amtToRead);//将buf_中pos_开始的amtToRead个字节copy到buf中
consumeBuffer(amtToRead);//将可读数据的开始位置增加amtToRead
}
return amtToRead;
}
//不支持写
@Override
public void write(byte[] buf, int off, int len) throws TTransportException {
throw new UnsupportedOperationException("No writing allowed!");
}
@Override
public byte[] getBuffer() {
return buf_;
}
public int getBufferPosition() {
return pos_;
}
//剩余可读的数据大小
public int getBytesRemainingInBuffer() {
return endPos_ - pos_;
}
//将可读数据的开始位置向后移len
public void consumeBuffer(int len) {
pos_ += len;
}
}

    TNonblockingTransport    

      TNonblockingTransport是TTransport的非阻塞抽象子类。

public abstract class TNonblockingTransport extends TTransport {
//连接初始化,参考SocketChannel.connect
public abstract boolean startConnect() throws IOException;
//连接完成,SocketChannel.finishConnect()
public abstract boolean finishConnect() throws IOException;
//注册到selector
public abstract SelectionKey registerSelector(Selector selector, int interests) throws IOException;
//读数据到buffer中
public abstract int read(ByteBuffer buffer) throws IOException;
//将buffer中的数据写出
public abstract int write(ByteBuffer buffer) throws IOException;
}

    TNonblockingSocket

      TNonblockingSocket是TNonblockingTransport的子类,是非阻塞Socket的实现,用于异步客户端。

public class TNonblockingSocket extends TNonblockingTransport {
private static final Logger LOGGER = LoggerFactory.getLogger(TNonblockingSocket.class.getName());
private final SocketAddress socketAddress_;//Host and port info,用于非阻塞连接懒加载
private final SocketChannel socketChannel_;//Java NIO中实现非阻塞读写的核心类
//一波构造函数
public TNonblockingSocket(String host, int port) throws IOException {
this(host, port, 0);
}
public TNonblockingSocket(String host, int port, int timeout) throws IOException {
this(SocketChannel.open(), timeout, new InetSocketAddress(host, port));
}
public TNonblockingSocket(SocketChannel socketChannel) throws IOException {
this(socketChannel, 0, null);
if (!socketChannel.isConnected()) throw new IOException("Socket must already be connected");
}
private TNonblockingSocket(SocketChannel socketChannel, int timeout, SocketAddress socketAddress)
throws IOException {
socketChannel_ = socketChannel;
socketAddress_ = socketAddress;
socketChannel.configureBlocking(false);//设置socketChannel为非阻塞
Socket socket = socketChannel.socket();
socket.setSoLinger(false, 0);
socket.setTcpNoDelay(true);
setTimeout(timeout);
}
//将SocketChannel注册到selector上的感兴趣事件,当感兴趣事件就绪时会收到notify
public SelectionKey registerSelector(Selector selector, int interests) throws IOException {
return socketChannel_.register(selector, interests);
}
public void setTimeout(int timeout) {
try {
socketChannel_.socket().setSoTimeout(timeout);
} catch (SocketException sx) {
LOGGER.warn("Could not set socket timeout.", sx);
}
}
public SocketChannel getSocketChannel() {
return socketChannel_;
}
//检查是否处于连接状态
public boolean isOpen() {
// isConnected() does not return false after close(), but isOpen() does
return socketChannel_.isOpen() && socketChannel_.isConnected();
}
//不要调用该方法,该实现类提供了自己的懒加载方法startConnect()用于打开连接
public void open() throws TTransportException {
throw new RuntimeException("open() is not implemented for TNonblockingSocket");
}
//读数据到buffer中
public int read(ByteBuffer buffer) throws IOException {
return socketChannel_.read(buffer);
}
//读指定数据到buf中,通过socketChannel_实现
public int read(byte[] buf, int off, int len) throws TTransportException {
if ((socketChannel_.validOps() & SelectionKey.OP_READ) != SelectionKey.OP_READ) {
throw new TTransportException(TTransportException.NOT_OPEN,
"Cannot read from write-only socket channel");
}
try {
return socketChannel_.read(ByteBuffer.wrap(buf, off, len));
} catch (IOException iox) {
throw new TTransportException(TTransportException.UNKNOWN, iox);
}
}
//将buffer中的数据写出
public int write(ByteBuffer buffer) throws IOException {
return socketChannel_.write(buffer);
}
//将buffer中的指定数据写出
public void write(byte[] buf, int off, int len) throws TTransportException {
if ((socketChannel_.validOps() & SelectionKey.OP_WRITE) != SelectionKey.OP_WRITE) {
throw new TTransportException(TTransportException.NOT_OPEN,
"Cannot write to write-only socket channel");
}
try {
socketChannel_.write(ByteBuffer.wrap(buf, off, len));
} catch (IOException iox) {
throw new TTransportException(TTransportException.UNKNOWN, iox);
}
}
//socketChannel_不支持
public void flush() throws TTransportException {
}
//关闭socket
public void close() {
try {
socketChannel_.close();
} catch (IOException iox) {
LOGGER.warn("Could not close socket.", iox);
}
}
//开始初始化
public boolean startConnect() throws IOException {
return socketChannel_.connect(socketAddress_);
}
//是否完成连接
public boolean finishConnect() throws IOException {
return socketChannel_.finishConnect();
}
}

    TServerTransport

      服务端Transport层共同的父类,主要包括开启监听和接收客户端连接请求两个方法。

public abstract class TServerTransport {
//开启监听客户端连接
public abstract void listen() throws TTransportException;
//连接请求到达后,创建transport实例
public final TTransport accept() throws TTransportException {
TTransport transport = acceptImpl();//具体方法由子类实现
if (transport == null) {
throw new TTransportException("accept() may not return NULL");
}
return transport;
}
//关闭监听
public abstract void close();
protected abstract TTransport acceptImpl() throws TTransportException;
public void interrupt() {}
}

    TServerSocket

      阻塞服务时使用,TServerSocket对ServerSocket类进行包装,具体实现由TServerSocket完成,代码相对比较简单。

public class TServerSocket extends TServerTransport {
private static final Logger LOGGER = LoggerFactory.getLogger(TServerSocket.class.getName());
private ServerSocket serverSocket_ = null;//基于ServerSocket实现
private int clientTimeout_ = 0;//接收Client连接请求的超时时间
public TServerSocket(ServerSocket serverSocket) {
this(serverSocket, 0);
}
//几个构造函数略过。。。创建TServerSocket实例
public TServerSocket(InetSocketAddress bindAddr, int clientTimeout) throws TTransportException {
clientTimeout_ = clientTimeout;
try {
serverSocket_ = new ServerSocket();
serverSocket_.setReuseAddress(true);
serverSocket_.bind(bindAddr);// Bind to listening port
} catch (IOException ioe) {
serverSocket_ = null;
throw new TTransportException("Could not create ServerSocket on address " + bindAddr.toString() + ".");
}
}
public void listen() throws TTransportException {
if (serverSocket_ != null) {
try {
serverSocket_.setSoTimeout(0);//等待客户端连接的超时时间,0表示无限超时
} catch (SocketException sx) {
LOGGER.error("Could not set socket timeout.", sx);
}
}
}
//accept客户端连接并封装为TSocket
protected TSocket acceptImpl() throws TTransportException {
if (serverSocket_ == null) {
throw new TTransportException(TTransportException.NOT_OPEN, "No underlying server socket.");
}
try {
Socket result = serverSocket_.accept();
TSocket result2 = new TSocket(result);
result2.setTimeout(clientTimeout_);
return result2;
} catch (IOException iox) {
throw new TTransportException(iox);
}
}
//关闭serverSocket_
public void close() {
if (serverSocket_ != null) {
try {
serverSocket_.close();
} catch (IOException iox) {
LOGGER.warn("Could not close server socket.", iox);
}
serverSocket_ = null;
}
}
public void interrupt() {
close();
}
public ServerSocket getServerSocket() {
return serverSocket_;
}
}

    TNonblockingServerTransport

      TNonblockingServerTransport是非阻塞实现的抽象基类,定义了一个向Selector注册对象的抽象方法。

public abstract class TNonblockingServerTransport extends TServerTransport {
public abstract void registerSelector(Selector selector);
}

    TNonblockingServerSocket

      TNonblockingServerSocket是TNonblockingServerTransport的具体实现,对ServerSocketChannel的封装。

public class TNonblockingServerSocket extends TNonblockingServerTransport {
private static final Logger LOGGER = LoggerFactory.getLogger(TNonblockingServerTransport.class.getName());
private ServerSocketChannel serverSocketChannel = null;//接收Client请求,Java NIO中的Channel
private ServerSocket serverSocket_ = null;//serverSocketChannel中的对象
private int clientTimeout_ = 0;//客户端连接建立超时时间
//几个构造函数略过。。。创建TNonblockingServerSocket实例
public TNonblockingServerSocket(InetSocketAddress bindAddr, int clientTimeout) throws TTransportException {
clientTimeout_ = clientTimeout;
try {
serverSocketChannel = ServerSocketChannel.open();//创建serverSocketChannel实例
serverSocketChannel.configureBlocking(false);//设置为非阻塞
serverSocket_ = serverSocketChannel.socket();//创建serverSocket_实例
serverSocket_.setReuseAddress(true);
serverSocket_.bind(bindAddr);//绑定监听端口
} catch (IOException ioe) {
serverSocket_ = null;
throw new TTransportException("Could not create ServerSocket on address " + bindAddr.toString() + ".");
}
}
//开启监听客户端连接
public void listen() throws TTransportException {
if (serverSocket_ != null) {
try {
serverSocket_.setSoTimeout(0);//等待客户端连接的超时时间,0表示无限超时
} catch (SocketException sx) {
sx.printStackTrace();
}
}
}
//接收客户端连接的具体实现,接收客户端连接并封装为TNonblockingSocket返回
protected TNonblockingSocket acceptImpl() throws TTransportException {
if (serverSocket_ == null) {
throw new TTransportException(TTransportException.NOT_OPEN, "No underlying server socket.");
}
try {
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel == null) {
return null;
}
TNonblockingSocket tsocket = new TNonblockingSocket(socketChannel);
tsocket.setTimeout(clientTimeout_);
return tsocket;
} catch (IOException iox) {
throw new TTransportException(iox);
}
}
//向selector注册OP_ACCEPT事件,接收新的连接
public void registerSelector(Selector selector) {
try {
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (ClosedChannelException e) {
}
}
//关闭serverSocket_
public void close() {
if (serverSocket_ != null) {
try {
serverSocket_.close();
} catch (IOException iox) {
LOGGER.warn("WARNING: Could not close server socket: " + iox.getMessage());
}
serverSocket_ = null;
}
}
public void interrupt() {
close();
}
}

  总结

    注意介绍了TTransport的实现方式。

参考资料

  Thrift源码系列----2.TTransport层源码分析

  

    

  

RPC-Thrift(二)的更多相关文章

  1. Thrift RPC实战(二) Thrift 网络服务模型

    限于篇幅关系,在观察源码的时候,只列举了部分源代码 TServer类层次体系 TSimpleServer/TThreadPoolServer是阻塞服务模型 TNonblockingServer/THs ...

  2. JAVA RPC(二)序列化协议杂谈

    序列化和反序列化作为Java里一个较为基础的知识点,大家心里也有那么几句要说的,但我相信很多小伙伴掌握的也就是那么几句而已,如果再深究问一下Java如何实现序列化和反序列化的,就可能不知所措了!遥记当 ...

  3. 聊聊RPC原理二

    之前写了一篇关于RPC的文章,浏览量十分感人:),但是感觉文章写得有些粗,觉得很多细节没有讲出来,这次把里边的细节再次补充和说明. 这次主要说的内容分为: 1. RPC的主要结构图. 2.分析结构图的 ...

  4. 老王讲自制RPC框架.(二.动态代理)

    (#简介) 什么是动态代理?动态代理是实现阶段不关心代理是谁,而在运行阶段才指定代理对象是哪一个,动态代理在做框架方面使用非常 广泛,比如spring的aop,其核心就是采用动态代理机制,下面让我们来 ...

  5. [development][thrift] RPC框架 thrift

    一: wiki:https://zh.wikipedia.org/wiki/Thrift 二: 来自IBM的介绍:https://www.ibm.com/developerworks/cn/java/ ...

  6. Thrift的TCompactProtocol紧凑型二进制协议分析

    Thrift的紧凑型传输协议分析: 用一张图说明一下Thrift的TCompactProtocol中各个数据类型是怎么表示的. 报文格式编码: bool类型: 一个字节. 如果bool型的字段是结构体 ...

  7. [转] thrift的使用介绍

    http://gemantic.iteye.com/blog/1199214 一.About  thrift   二.什么是thrift,怎么工作? 三.Thrift  IDL 四.Thrift   ...

  8. .NET Core微服务之服务间的调用方式(REST and RPC)

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.REST or RPC ? 1.1 REST & RPC 微服务之间的接口调用通常包含两个部分,序列化和通信协议.常见的序列化 ...

  9. REST RPC HTTP vs 高性能二进制协议 序列化和通信协议

    edisonchou https://mp.weixin.qq.com/s/-XZXqXawR-NxJMPCeiNsmg .NET Core微服务之服务间的调用方式(REST and RPC) Edi ...

  10. Thrift 原理与使用实例

    一.Thrift 框架介绍 1.前言 Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目.Thrift通过一个中间语言(IDL, 接口定 ...

随机推荐

  1. Hibernate-ORM:13.Hibernate中的连接查询

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客将会解释Hibernate中的连接查询(各种join) 一,目录 1.内链接 1.1显式内连接(inn ...

  2. 【多校联合】(HDU6095)Rikka with Competition

    题意:给定$n$个数,代表$n$个选手的能量高低,现在再给一个$k$,任意在$n$个选手中挑取两个选手比赛,如果$|a_i−a_j|>K$,那么能量高的选手获胜,另一个将被淘汰,否则两个人都有机 ...

  3. vi/vim 命令使用详解

    1.Linux下创建文件 vi test.txt 或者 vim test.txt 或者 touch test.txt 2.vi/vim 使用 基本上 vi/vim 共分为三种模式,分别是命令模式(Co ...

  4. Qt Qwdget 汽车仪表知识点拆解8 淡入效果

    先贴上效果图,注意,没有写逻辑,都是乱动的 看下面的开始,开始的时候有一个带入的效果,这里有一个坑, 网上大部分都是调用下面这个函数 setWindowOpacity(); 但是,你会发现,在你的子窗 ...

  5. cocos2d-x 精灵

    Sprite有两个父类:BatchableNode批量创建精灵(大量重复的比如子弹)和pyglet.sprite.Sprite. 精灵的创建

  6. kafka常用命令笔记

    0.查看有哪些主题: ./kafka-topics.sh --list --zookeeper 192.168.0.201:12181 1.查看topic的详细信息 ./kafka-topics.sh ...

  7. LeetCode - 35. Search Insert Position(48ms)

    Given a sorted array and a target value, return the index if the target is found. If not, return the ...

  8. LeetCode 622——设计循环队列

    1. 题目 设计你的循环队列实现. 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环.它也被称为"环形缓冲器". 循环队列 ...

  9. SpringMVC 上传图片保存到服务器 同时更改图片名称保存至数据库

    @RequestMapping(value = "/save.do", method = RequestMethod.POST)    public String saveDriv ...

  10. gdb调试行号错位

    http://blog.csdn.net/wangxmin2005/article/details/8128192 gdb调试过程中出现行号错位的情况,原因一般有两个: 1. 编译器的优化可能把某些语 ...