Thrift之双向通讯
在实际应用中,却经常会有客户端建立连接后,等待服务端数据的长连接模式,也可以称为双向连接。
一、双连接,服务端与客户端都开ThriftServer
如果网络环境可控,可以让服务端与客户端互相访问,你可以给服务端与客户端,两者都开一个ThriftServer,也就是两者互为服务端与客户端。这样就可以简单实现互相访问,比如:
客户端: <-------------------> 服务端:
ThriftClient --------------> ThriftService
ThriftService <------------- ThriftClient
二、单连接,利用ProcessorFactory中TConnectionInfo的transport定时向客户端发送消息,让thrift保持长连接不立即关闭。
thrift是rpc结构的通信框架,rpc结构默认是 【客户端请求 -> 服务端回应 -> 连接断开】 的这种短连接形式,因此rpc默认是没有服务端回调功能,自然也没有长连接。
如果要保持连接不关闭且被动接收到对方的数据,需要指定双方连接的service必须为oneway,服务端定时向客户端发送信息(利用客户端发送数据到服务端时连接成功时产生的transport,需客户端也创建服务Processor),同时客户端实时检测transport的状态,以便出现与服务端连接断开的情况出现。具体流程:
1、双向连接的service必须为oneway,否则会因为recv函数抛出remote close异常。
2、客户端重用建立client的protocol,开线程使用processor.Process(protocol,protocol)监听服务端回调发送过来的消息。
3、服务端Processor的创建,使用ProcessorFactory创建Processor,通过getProcessor函数中transport作为向客户端发送消息的client的transport而创建一个Processor。
java实例
定义test.thrift
namespace java com.zychen.thrift
service ClientHandshakeService{
oneway void HandShake();
}
service ServerCallbackService{
oneway void Push(1: string msg);
}
生成接口代码
把thrift-0.9.3.exe和test.thrift文件放在同一个目录。
进入DOS命令执行:thrift-0.9.3.exe --gen java test.thrift
生成文件gen-java/ com/zychen/thrift/Test.java
服务端代码
ClientHandshakeServiceHandler.java
package com.zychen.thrift;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TTransport;
public class ClientHandshakeServiceHandler implements ClientHandshakeService.Iface {
public ClientHandshakeServiceHandler(TTransport trans){
client = new ServerCallbackService.Client(new TBinaryProtocol(trans));
}
@Override
public void HandShake() throws TException {
System.out.println("HandShake\n");
StartThread();
}
//开始线程
public void StartThread(){
if(threadCallback == null){
stopThread = false;
threadCallback = new Thread(new CallbackThread());
threadCallback.start();
}
}
//停止线程
public void StopThread(){
stopThread = true;
if(threadCallback != null){
try {
threadCallback.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
threadCallback = null;
}
}
@Override
protected void finalize() throws Throwable {
// TODO Auto-generated method stub
StopThread();
super.finalize();
}
protected ServerCallbackService.Client client;
protected boolean stopThread = false;
protected Thread threadCallback = null;
class CallbackThread implements Runnable {
public void run() {
while(true){
if(stopThread){
break;
}
try {
client.Push("aaaaaaa");
Thread.sleep(50);
} catch (TException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
}
}
};
}
ProcessorFactoryImpl.java
package com.zychen.thrift;
import org.apache.thrift.TProcessor;
import org.apache.thrift.TProcessorFactory;
import org.apache.thrift.transport.TTransport;
import com.zychen.thrift.ClientHandshakeService.Processor;
public class ProcessorFactoryImpl extends TProcessorFactory {
public ProcessorFactoryImpl(TProcessor processor) {
super(processor);
// TODO Auto-generated constructor stub
}
@Override
public TProcessor getProcessor(TTransport trans) {
// TODO Auto-generated method stub
//return super.getProcessor(trans);
return new ClientHandshakeService.Processor(new ClientHandshakeServiceHandler(trans));
}
}
ServerTest.java
package com.zychen.thrift;
import org.apache.thrift.TProcessorFactory;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TBinaryProtocol.Factory;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.server.TThreadPoolServer.Args;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TTransportException;
import com.zychen.thrift.ClientHandshakeService.Processor;
public class ServerTest {
/**
* @param args
*/
public static void main(String[] args) {
TServerSocket tServerSocket;
try {
tServerSocket = new TServerSocket(9999);
TThreadPoolServer.Args targs = new TThreadPoolServer.Args(tServerSocket);
TBinaryProtocol.Factory factory = new TBinaryProtocol.Factory();
//获取processFactory
TProcessorFactory tProcessorFactory = new ProcessorFactoryImpl(null);
targs.protocolFactory(factory);
targs.processorFactory(tProcessorFactory);
TThreadPoolServer tThreadPoolServer = new TThreadPoolServer(targs);
System.out.println("start server...");
tThreadPoolServer.serve();
} catch (TTransportException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
客户端代码
ServerCallbackServiceImpl.java
package com.zychen.thrift;
import java.io.IOException;
import org.apache.thrift.TException;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TSocket;
public class ServerCallbackServiceImpl implements ServerCallbackService.Iface{
public ServerCallbackServiceImpl(TSocket socket){
this.socket = socket;
}
@Override
public void Push(String msg) throws TException {
// TODO Auto-generated method stub
String str = String.format("receive msg %d: %s", nMsgCount++, msg);
System.out.println(str);
}
public void process(){
processor = new ServerCallbackService.Processor<ServerCallbackService.Iface>(this);
TBinaryProtocol protocol = new TBinaryProtocol(socket);
while (true)
{
try
{
//TProcessor,负责调用用户定义的服务接口,从一个接口读入数据,写入一个输出接口
while (processor.process(protocol, protocol)){
//阻塞式方法,不需要内容
System.out.println("走阻塞式方法");
//关闭socket
//socket.close();
}
//connection lost, return
return;
}catch (TException e){
System.out.println("连接已断开...");
e.printStackTrace();
return;
}
}
}
protected int nMsgCount = 0;
protected TSocket socket;
protected TProcessor processor;
}
ClientTest.java
package com.zychen.thrift;
import java.io.IOException;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransportException;
import com.zychen.thrift.ServerCallbackService.Iface;
public class ClientTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
TSocket tSocket = new TSocket("localhost",9999);
ClientHandshakeService.Client client = new ClientHandshakeService.Client(new TBinaryProtocol(tSocket));
try {
tSocket.open();
runMethod(tSocket);
//向服务端发送消息
for (int i = 0; i < 100; ++i){
client.HandShake();
Thread.sleep(50);
}
System.in.read();
tSocket.close();
} catch (TTransportException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void runMethod(final TSocket tSocket){
Thread thread = new Thread(new Runnable(){
ServerCallbackServiceImpl serverCallbackServiceImpl = new ServerCallbackServiceImpl(tSocket);
@Override
public void run() {
// TODO Auto-generated method stub
serverCallbackServiceImpl.process();
}
});
thread.start();
};
}
完整代码:下载参考资料:
http://www.cnblogs.com/xiaosuiba/p/4122459.html
http://blog.csdn.net/qq_27989757/article/details/50761051
Thrift之双向通讯的更多相关文章
- 重温WCF之数单向通讯、双向通讯、回调操作(五)
一.单向通讯单向操作不等同于异步操作,单向操作只是在发出调用的瞬间阻塞客户端,但如果发出多个单向调用,WCF会将请求调用放入到服务器端的队列中,并在某个时间进行执行.队列的存储个数有限,一旦发出的调用 ...
- silverlight与wcf双向通讯 例子
本文将建立一个silverlight与wcf双向通讯的简单实例,以下是详细步骤: 新建Silverlight应用程序,名称WCFtest.解决方案中添加WCF服务应用程序,名称WcfServiceTe ...
- C++的MFC 与 HTML 双向通讯
C++中嵌入ie浏览器总结(1) - ie边框 及上下文菜单 最近项目中用html 来做界面,也就折腾了一下在wxwidget中嵌入浏览器的若干细节工作,mfc也基本是类似的,由于wxwidget中已 ...
- 我们一起学习WCF 第四篇单通讯和双向通讯
前言:由于个人原因很久没有更新这个系列了,我会继续的更新这系列的文章.这一章是单向和双向通讯.所谓的单向就是只有发送却没有回复,双向是既有发送还有回复.就是有来无往代表单向,礼尚往来表示双向.下面我用 ...
- Thrift实现C#通讯服务程序
Thrift初探:简单实现C#通讯服务程序 好久没有写文章了,由于换工作了,所以一直没有时间来写博.今天抽个空练练手下~最近接触了下Thrift,网上也有很多文章对于Thrift做了说明: ...
- iPhone 和 iPad的ios 开发中 利用 WebViewJavascriptBridge组件,通过 UIWebView 对Html进行双向通讯
本文转载至 http://blog.csdn.net/remote_roamer/article/details/7261490 WebViewJavascriptBridge 项目的 官网 http ...
- 基于grpc的流式方式实现双向通讯(python)
grpc介绍 grpc是谷歌开源的一套基于rpc实现的通讯框架(官网有更完整的定义).在搞懂grpc之前,首先要弄懂rpc是什么.下面是自己理解的rpc定义,若有不对,望指出: rpc官方称为 远程过 ...
- Oracle VirtualBox 使用桥接网络完成主机和虚拟机之间的双向通讯
最近刚换了新的笔记本电脑,终于使用上intel i7处理器,可以使用硬件虚拟化技术安装系统.配置如下: 主机 ThinkPad P50s OS Window 10 虚拟机软件 Orac ...
- 通过桥接虚拟网卡使VMWare和宿主机实现双向通讯
0.为什么选择虚拟网卡和桥接模式 首先虚拟机网络设置为NAT,虚拟机实现上网是很方便的,但是宿主机访问虚拟机就比较麻烦了(需要单独配置端口转发),桥接就能很好的解决这个问题,桥接模式会把虚拟机当做宿主 ...
随机推荐
- 【Python】【元编程】【从协议到抽象基类】
"""class Vector2d: typecode = 'd' def __init__(self,x,y): self.__x = float(x) self.__ ...
- canvas 实现鼠标画出矩形
<!doctype html> <html> <head> <meta charset="UTF-8"> <meta name ...
- 《剑指offer》第七题(重要!重建二叉树)
文件一:main.cpp // 面试题:重建二叉树 // 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输 // 入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历 ...
- html & js 单双引号
1.html使用双引号,嵌套亦如此,表示dom元素的属性 <input value="Test" type="button" onclick=" ...
- 【Golang】Debug :decoding dwarf section info at offset 0x0: too short
解决方法 通过下面的方式升级dlv 来解决这个问题: go get -u github.com/derekparker/delve/cmd/dlv 下面是我记录的定位问题的过程 问题描述 博主升级到了 ...
- 大年三十。让字母在屏幕上奔跑:(sleep , system"clear")
system "clear",ruby清屏(osk系统上,window上用system "cls"). https://stackoverflow.com/qu ...
- android--------listview之适配器
ListView之适配器的使用,包含了ArrayAdapter,SimpleAdapter ,BaseAdapter等适配器. 1:ArrayAdapter /**** * * * ArrayAdap ...
- mac 安装nginx,并配置nginx的运行环境
1. 安装nginx // 查询有没有nginx brew search nginx //开始安装nignx brew install nginx 2. 检查nignx是否安装成功 nginx -V ...
- 『Sklearn』特征向量化处理
『Kaggle』分类任务_决策树&集成模型&DataFrame向量化操作 1 2 3 4 5 6 7 8 9 '''特征提取器''' from sklearn.feature_extr ...
- 『Nltk』常用方法
引言 在nltk的介绍文章中,前面几篇主要介绍了nltk自带的数据(书籍和语料),感觉系统学习意义不大,用到哪里看到那里就行(笑),所以这里会从一些常用功能开始,适当略过对于数据本体的介绍. 文本处理 ...