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. Anytime项目开发记录0

    Anytime,中文名:我很忙. 开发者:孤独的猫咪神. 这个项目会持续更新,直到我决定不再维护这个APP. 2014年3月10日:近日有事,暂时断更.希望可以会尽快完事. 2014年3月27日:很抱 ...

  2. github简单使用教程(转)

    github是一个基于git的代码托管平台,付费用户可以建私人仓库,我们一般的免费用户只能使用公共仓库,也就是代码要公开.对于一般人来说公共仓库就已经足够了,而且我们也没多少代码来管理,O(∩_∩)O ...

  3. Python request 简单使用

    Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库.它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTT ...

  4. JavaScript RegExp 身份证、账号密码、email正则

    什么是正则表达式 正则表达式是构成搜索模式. 在文本中搜索数据时,可以使用此搜索模式来描述正在搜索的内容. 正则表达式可以是单个字符,也可以是更复杂的模式. 正则表达式可用于执行所有类型的文本搜索和文 ...

  5. 多文件上传 input 的multiple 属性

    一.上传多张图片并且预览 HTML: <div class="container"> <label>请选择一个图像文件:</label> < ...

  6. [leetcode-651-4 Keys Keyboard]

    Imagine you have a special keyboard with the following keys: Key 1: (A): Prints one 'A' on screen. K ...

  7. java--List转换成json格式

    方法一 首先导入jar包,json-rpc-1.0.jar public class List2Json { public static JSONArray ProLogList2Json(List& ...

  8. .Net 面试总结

    今天去面试了一家公司,做电子商务类的网站的,公司的老板应该比较有能量,可以同时拿下若干项目,技术负责人给提了几个问题: 记不清顺序了 .net 构析函数的作用 泛型的主要作用及应用方面 结构与类的区别 ...

  9. 【SSH】——Struts2中的动态方法调用(二)

    当action中的方法有很多时,那应该怎么调用呢?上次我们提到的UserAction类中只有一个execute方法,如果我们需要增加用户的增删改查方法,如下: public class UserAct ...

  10. CentOS7 php 安装 amqp扩展

    继续安装完 rabbitmq后,安装最新 php amqp扩展 http://www.cnblogs.com/8000cabbage/p/7788575.html 参考:carson 1.安装rabb ...