在实际应用中,却经常会有客户端建立连接后,等待服务端数据的长连接模式,也可以称为双向连接。
一、双连接,服务端与客户端都开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之双向通讯的更多相关文章

  1. 重温WCF之数单向通讯、双向通讯、回调操作(五)

    一.单向通讯单向操作不等同于异步操作,单向操作只是在发出调用的瞬间阻塞客户端,但如果发出多个单向调用,WCF会将请求调用放入到服务器端的队列中,并在某个时间进行执行.队列的存储个数有限,一旦发出的调用 ...

  2. silverlight与wcf双向通讯 例子

    本文将建立一个silverlight与wcf双向通讯的简单实例,以下是详细步骤: 新建Silverlight应用程序,名称WCFtest.解决方案中添加WCF服务应用程序,名称WcfServiceTe ...

  3. C++的MFC 与 HTML 双向通讯

    C++中嵌入ie浏览器总结(1) - ie边框 及上下文菜单 最近项目中用html 来做界面,也就折腾了一下在wxwidget中嵌入浏览器的若干细节工作,mfc也基本是类似的,由于wxwidget中已 ...

  4. 我们一起学习WCF 第四篇单通讯和双向通讯

    前言:由于个人原因很久没有更新这个系列了,我会继续的更新这系列的文章.这一章是单向和双向通讯.所谓的单向就是只有发送却没有回复,双向是既有发送还有回复.就是有来无往代表单向,礼尚往来表示双向.下面我用 ...

  5. Thrift实现C#通讯服务程序

    Thrift初探:简单实现C#通讯服务程序 好久没有写文章了,由于换工作了,所以一直没有时间来写博.今天抽个空练练手下~最近接触了下Thrift,网上也有很多文章对于Thrift做了说明:       ...

  6. iPhone 和 iPad的ios 开发中 利用 WebViewJavascriptBridge组件,通过 UIWebView 对Html进行双向通讯

    本文转载至 http://blog.csdn.net/remote_roamer/article/details/7261490 WebViewJavascriptBridge 项目的 官网 http ...

  7. 基于grpc的流式方式实现双向通讯(python)

    grpc介绍 grpc是谷歌开源的一套基于rpc实现的通讯框架(官网有更完整的定义).在搞懂grpc之前,首先要弄懂rpc是什么.下面是自己理解的rpc定义,若有不对,望指出: rpc官方称为 远程过 ...

  8. Oracle VirtualBox 使用桥接网络完成主机和虚拟机之间的双向通讯

    最近刚换了新的笔记本电脑,终于使用上intel i7处理器,可以使用硬件虚拟化技术安装系统.配置如下: 主机      ThinkPad P50s   OS Window 10 虚拟机软件  Orac ...

  9. 通过桥接虚拟网卡使VMWare和宿主机实现双向通讯

    0.为什么选择虚拟网卡和桥接模式 首先虚拟机网络设置为NAT,虚拟机实现上网是很方便的,但是宿主机访问虚拟机就比较麻烦了(需要单独配置端口转发),桥接就能很好的解决这个问题,桥接模式会把虚拟机当做宿主 ...

随机推荐

  1. JS进阶系列之this

    在javascript中,this的指向是在执行上下文的创建阶段确定的,其实只要知道不同执行方式下,this的指向分别是是什么,就能很好的掌握this这个让人摸不透的东西. 一.全局执行 全局执行又分 ...

  2. HTTP协议中TCP的三次握手 and HTTPS

    https://www.cnblogs.com/zxh930508/p/5432700.html https://www.cnblogs.com/digdeep/p/4832885.html

  3. 微信网页跳转页面常见bug处理

    微信网页跳转页面常见bug处理 1.不要直接用a链接直接跳转 2.url后加上时间戳 function gohome() { window.location.href = "../home/ ...

  4. 用 Excel 生成和管理 Markdown 表格--转载

    Markdown 作为一种轻量级的标记语言,用来进行简单的文本排版,确实方便快捷.但 Markdown 标记语言的属性,也使得其在表格处理上略显繁琐且不直观.而 Excel 几乎就是表格的代名词,借助 ...

  5. H5图片预览、压缩、上传

    目标实现: 1.选择图片, 前端预览效果 2.图片大于1.2M的时候, 对图片进行压缩 3.以表单的形式上传图片 4.图片删除 预览效果图: 代码说明: 1.input:file选择图片 <!- ...

  6. Codeforces Round #223 (Div. 2) E. Sereja and Brackets 线段树区间合并

    题目链接:http://codeforces.com/contest/381/problem/E  E. Sereja and Brackets time limit per test 1 secon ...

  7. Yandex.Algorithm 2011 Round 2 D. Powerful array 莫队

    题目链接:点击传送 D. Powerful array time limit per test 5 seconds memory limit per test 256 megabytes input ...

  8. Cocos2d-x学习笔记(五)调度

    在init方法中增加下边的代码,建议使用schedule函数,而不是scheduleUpdate函数,因为,后者默认是调用update函数,在如果有多个函数需要调度时,不是很灵活. auto labe ...

  9. STL_算法_02_排序算法

    ◆ 常用的排序算法: 1.1.合并(容器A(全部/部分)&容器B(全部/部分)==>容器C(全部/部分),容器C中元素已经排好顺序),返回的值==>iteratorOutBegin ...

  10. 01_DllZZ.cpp

    1. // DllZZ.cpp : Defines the entry point for the DLL application. // #include "stdafx.h" ...