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,虚拟机实现上网是很方便的,但是宿主机访问虚拟机就比较麻烦了(需要单独配置端口转发),桥接就能很好的解决这个问题,桥接模式会把虚拟机当做宿主 ...
随机推荐
- bzoj 1832 lca
1832: [AHOI2008]聚会 Time Limit: 10 Sec Memory Limit: 64 MB Description Y岛风景美丽宜人,气候温和,物产丰富.Y岛上有N个城市,有 ...
- Goroutines和Channels(二)
网络编程是并发大显身手的一个领域,由于服务器是最典型的需要同时处理很多连接的程序,这些连接一般来自于彼此独立的客户端. 本小节,我们会讲解go语言的net包,这个包提供编写一个网络客户端或者服务器程序 ...
- Java入门:零碎的知识点
实例变量经常被称为属性 成员变量和局部变量:前者在类中定义,后者在类的方法中定义且系统不会自动赋初始值 我们创建一个对象的时候实际上执行的是无参的构造方法 静态变量 static String arr ...
- RetinaNet论文理解
引言 介绍 目前精度高的检测器都是基于two-stage,proposal-driven机制,第一阶段生成稀疏的候选对象位置集,第二阶段使用CNN进一步将每个候选位置分为前景或者背景以及确定其类别: ...
- img srcset 和 sizes
img srcset 和 sizes 诞生的目的是解决图片清晰度和节省加载图片大小问题,比方说我需要在retina高的硬件上看到更细腻的图片,又或者我要在电脑看到的图片和在手机上的图片不一样. 解 ...
- 3-19(晚) require_relative 和 require. === operator的解释。
kernel#require_relative Ruby tries to load the library named string relative to the requiring file's ...
- android--------volley之网络请求和图片加载
Volley是 Google 推出的 Android 异步网络请求框架和图片加载框架. Volley的特性 封装了的异步的请求API.Volley 中大多是基于接口的设计,可配置性强. 一个优雅和稳健 ...
- Razor及HtmlHelper学习笔记
Razor 不是编程语言.它是服务器端标记语言. 什么是Razor? Razor 是一种允许您向网页中嵌入基于服务器的代码(Visual Basic 和 C#)的标记语法. 当网页被写入浏览器时,基于 ...
- FastDFS install - 2
storage install nginx 1. update dependency package yum -y install pcre-devel openssl openssl-devel g ...
- ccf窗口
#include<iostream> #include<cstring> #include<algorithm> #include<vector> us ...