使用thrift实现了Java服务器和nodejs客户端之间的跨平台通信

1. 简单介绍

thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在
C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。

2. 下载与安装

Thrift目前最高0.9.2,地址:http://archive.apache.org/dist/thrift/

注意,我们要把exe和tar文件都下载下来,exe用来编译你的thrift中间语言,而tar解压后,我们可以看到csharp,php,java,js等多种开发语言的实例代码,对我们很有帮助的,下载最新版,其中包含lib文件库,包含各种语言需要的类库;

下载之后,我们把exe文件可放在C盘,建个Thrift目录,把它放入,然后可以配置一下环境变量;将thrift的文件夹路径添加到path变量中;

3. 编写thrift文件

首先编写:tutorial.thrift

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

# Thrift Tutorial
# Mark Slee ([email protected])
#
# This file aims to teach you how to use Thrift, in a .thrift file. Neato. The
# first thing to notice is that .thrift files support standard shell comments.
# This lets you make your thrift file executable and include your Thrift build
# step on the top line. And you can place comments like this anywhere you like.
#
# Before running this file, you will need to have installed the thrift compiler
# into /usr/local/bin.

/**
 * The first thing to know about are types. The available types in Thrift are:
 *
 *  bool        Boolean, one byte
 *  byte        Signed byte
 *  i16         Signed 16-bit integer
 *  i32         Signed 32-bit integer
 *  i64         Signed 64-bit integer
 *  double      64-bit floating point value
 *  string      String
 *  binary      Blob (byte array)
 *  map<t1,t2>  Map from one type to another
 *  list<t1>    Ordered list of one type
 *  set<t1>     Set of unique elements of one type
 *
 * Did you also notice that Thrift supports C style comments?
 */

// Just in case you were wondering... yes. We support simple C comments too.

/**
 * Thrift files can reference other Thrift files to include common struct
 * and service definitions. These are found using the current path, or by
 * searching relative to any paths specified with the -I compiler flag.
 *
 * Included objects are accessed using the name of the .thrift file as a
 * prefix. i.e. shared.SharedObject
 */
include "shared.thrift"

/**
 * Thrift files can namespace, package, or prefix their output in various
 * target languages.
 */
namespace cpp tutorial
namespace d tutorial
namespace java tutorial
namespace php tutorial
namespace perl tutorial
namespace haxe tutorial

/**
 * Thrift lets you do typedefs to get pretty names for your types. Standard
 * C style here.
 */
typedef i32 MyInteger

/**
 * Thrift also lets you define constants for use across languages. Complex
 * types and structs are specified using JSON notation.
 */
const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}

/**
 * You can define enums, which are just 32 bit integers. Values are optional
 * and start at 1 if not supplied, C style again.
 */
enum Operation {
  ADD = 1,
  SUBTRACT = 2,
  MULTIPLY = 3,
  DIVIDE = 4
}

/**
 * Structs are the basic complex data structures. They are comprised of fields
 * which each have an integer identifier, a type, a symbolic name, and an
 * optional default value.
 *
 * Fields can be declared "optional", which ensures they will not be included
 * in the serialized output if they aren't set.  Note that this requires some
 * manual management in some languages.
 */
struct Work {
  1: i32 num1 = 0,
  2: i32 num2,
  3: Operation op,
  4: optional string comment,
}

/**
 * Structs can also be exceptions, if they are nasty.
 */
exception InvalidOperation {
  1: i32 whatOp,
  2: string why
}

/**
 * Ahh, now onto the cool part, defining a service. Services just need a name
 * and can optionally inherit from another service using the extends keyword.
 */
service Calculator extends shared.SharedService {

  /**
   * A method definition looks like C code. It has a return type, arguments,
   * and optionally a list of exceptions that it may throw. Note that argument
   * lists and exception lists are specified using the exact same syntax as
   * field lists in struct or exception definitions.
   */

   void ping(),

   i32 add(1:i32 num1, 2:i32 num2),

   i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),

   /**
    * This method has a oneway modifier. That means the client only makes
    * a request and does not listen for any response at all. Oneway methods
    * must be void.
    */
   oneway void zip()

}

/**
 * That just about covers the basics. Take a look in the test/ folder for more
 * detailed examples. After you run this file, your generated code shows up
 * in folders with names gen-<language>. The generated code isn't too scary
 * to look at. It even has pretty indentation.
 */

附上shared.thrift

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/**
 * This Thrift file can be included by other Thrift files that want to share
 * these definitions.
 */

namespace cpp shared
namespace d share // "shared" would collide with the eponymous D keyword.
namespace java shared
namespace perl shared
namespace php shared
namespace haxe shared

struct SharedStruct {
  1: i32 key
  2: string value
}

service SharedService {
  SharedStruct getStruct(1: i32 key)
}

2、输入编译命令,将接口文件编译对应的语言java、nodejs;

>thrift -r --gen java tutorial.thrift

>thrift
-r --gen js:node tutorial.thrift

3、可以在当前目录下看到对应生成的文件夹gen-java、gen-nodejs;

    

4. 创建Java语言的服务器

1、在eclipse新建MavenProject名为thrift

2、创建CalculatorHandler.java和JavaServer.java文件。代码如下:

CalculatorHandler.java
package tutorial.impl;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

import java.util.HashMap;

import shared.SharedStruct;
// Generated code
import tutorial.Calculator;
import tutorial.InvalidOperation;
import tutorial.Work;

public class CalculatorHandler implements Calculator.Iface {

	private HashMap<Integer, SharedStruct> log;

	public CalculatorHandler() {
		log = new HashMap<Integer, SharedStruct>();
	}

	public void ping() {
		System.out.println("ping()");
	}

	public int add(int n1, int n2) {
		System.out.println("add(" + n1 + "," + n2 + ")");
		return n1 + n2;
	}

	public int calculate(int logid, Work work) throws InvalidOperation {
		System.out.println("calculate(" + logid + ", {" + work.op + "," + work.num1 + "," + work.num2 + "})");
		int val = 0;
		switch (work.op) {
		case ADD:
			val = work.num1 + work.num2;
			break;
		case SUBTRACT:
			val = work.num1 - work.num2;
			break;
		case MULTIPLY:
			val = work.num1 * work.num2;
			break;
		case DIVIDE:
			if (work.num2 == 0) {
				InvalidOperation io = new InvalidOperation();
				io.whatOp = work.op.getValue();
				io.why = "Cannot divide by 0";
				throw io;
			}
			val = work.num1 / work.num2;
			break;
		default:
			InvalidOperation io = new InvalidOperation();
			io.whatOp = work.op.getValue();
			io.why = "Unknown operation";
			throw io;
		}

		SharedStruct entry = new SharedStruct();
		entry.key = logid;
		entry.value = Integer.toString(val);
		log.put(logid, entry);

		return val;
	}

	public SharedStruct getStruct(int key) {
		System.out.println("getStruct(" + key + ")");
		return log.get(key);
	}

	public void zip() {
		System.out.println("zip()");
	}

}

3.JavaServer文件代码

package Server;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TServer.Args;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TSSLTransportFactory;
import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;

// Generated code
import tutorial.Calculator;
import tutorial.impl.CalculatorHandler;

public class JavaServer {

	public static CalculatorHandler handler;

	public static Calculator.Processor processor;

	public static void main(String[] args) {
		try {
			handler = new CalculatorHandler();
			processor = new Calculator.Processor(handler);

			Runnable simple = new Runnable() {
				public void run() {
					simple(processor);
				}
			};
			Runnable secure = new Runnable() {
				public void run() {
					secure(processor);
				}
			};

			new Thread(simple).start();
			new Thread(secure).start();
		} catch (Exception x) {
			x.printStackTrace();
		}
	}

	public static void simple(Calculator.Processor processor) {
		try {
			TServerTransport serverTransport = new TServerSocket(9090);
			TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));

			// Use this for a multithreaded server
			// TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));

			System.out.println("Starting the simple server...");
			server.serve();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void secure(Calculator.Processor processor) {
		try {
			/*
			 * Use TSSLTransportParameters to setup the required SSL parameters. In this example we are setting the keystore
			 * and the keystore password. Other things like algorithms, cipher suites, client auth etc can be set.
			 */
			TSSLTransportParameters params = new TSSLTransportParameters();
			// The Keystore contains the private key
			params.setKeyStore("c:/.mykeystore", "jinking", null, null);

			/*
			 * Use any of the TSSLTransportFactory to get a server transport with the appropriate SSL configuration. You can
			 * use the default settings if properties are set in the command line. Ex: -Djavax.net.ssl.keyStore=.keystore and
			 * -Djavax.net.ssl.keyStorePassword=thrift
			 *
			 * Note: You need not explicitly call open(). The underlying server socket is bound on return from the factory
			 * class.
			 */
			TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(9091, 0, null, params);
			TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));

			// Use this for a multi threaded server
			// TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));

			System.out.println("Starting the secure server...");
			server.serve();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

4、配置需要的lib类库,编辑pom.xml文件,必备的类库有libthrift和slf4j-api

		<dependency>
			<groupId>org.apache.thrift</groupId>
			<artifactId>libthrift</artifactId>
			<version>0.9.2</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.6.1</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>log4j-over-slf4j</artifactId>
			<version>1.6.1</version>
		</dependency>

5、用java目录下的keytool生成证书;

>keytool -certreq -keyalg RSA -alias myalias -file certreq.txt -keystore c:\.mykeystore

代码相应的修改成你生成的秘钥,红色字体标出;

params.setKeyStore("c:/.mykeystore", <span style="color:#ff0000;">"jinking"</span>, null, null);

6、运行javaServer.java文件,可以看到如下界面;

5. 创建nodejs版的客户端

1、首先就是要搭建nodejs环境和npm和express、安装对应模块;这个可以去网上搜索一下;不在此叙述;

可能会报错:Error: Cannot find module ‘thrift‘  和 Error: Cannot find module ‘node-int64‘ 、Error: Cannot find module ‘q‘

则需要输入下面的目录安装对应的模块:

npm install -g node-int64  和  npm install -g thrift 、  npm install -g q

2、新建工程目录client;

3、讲lib下的nodejs类库和gen-nodejs,拷贝到根目录下,路径如下:

4、创建NodeClient.js文件

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

var thrift = require('./thrift');
var ThriftTransports = require('./thrift/transport');
var ThriftProtocols = require('./thrift/protocol');
var Calculator = require('./gen-nodejs/Calculator');
var ttypes = require('./gen-nodejs/tutorial_types');

transport = ThriftTransports.TBufferedTransport()
protocol = ThriftProtocols.TBinaryProtocol()

var connection = thrift.createConnection("localhost", 9090, {
  transport : transport,
  protocol : protocol
});

connection.on('error', function(err) {
  assert(false, err);
});

// Create a Calculator client with the connection
var client = thrift.createClient(Calculator, connection);

client.ping(function(err, response) {
  console.log('ping()');
});

client.add(1,1, function(err, response) {
  console.log("1+1=" + response);
});

work = new ttypes.Work();
work.op = ttypes.Operation.DIVIDE;
work.num1 = 1;
work.num2 = 0;

client.calculate(1, work, function(err, message) {
  if (err) {
    console.log("InvalidOperation " + err);
  } else {
    console.log('Whoa? You know how to divide by zero?');
  }
});

work.op = ttypes.Operation.SUBTRACT;
work.num1 = 15;
work.num2 = 10;

client.calculate(1, work, function(err, message) {
  console.log('15-10=' + message);

  client.getStruct(1, function(err, message){
    console.log('Check log: ' + message.value);

    //close the connection once we're done
    connection.end();
  });
});

5、输入:>node NodeClient.js

6、nodejs客户端命令行窗口显示:

7、Java服务器端显示:

8、大功告成。

使用thrift框架实现了Java和nodejs之间的跨平台通信;

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-06 17:23:18

使用thrift实现了Java服务器和nodejs客户端之间的跨平台通信的相关文章

java服务器与c#客户端的字符编码问题

在服务器与客户端交互时,有时候服务器与客户端并不是拿同一种编程语言写的,这时候需要注意字符编码转换的问题.以java服务器和c#客户端为例,此时把c#端接收到的数据用GBK编码表示.  Encoding encoding = Encoding.GetEncoding("GBK");        //定义GBK编码            returnMsg = encoding.GetString(memStream.GetBuffer(), 0, memStream.GetBuffe

JAVA服务器与C#客户端的通信技术调研

JAVA服务器与C#客户端的通信技术调研 研究背景及目的: ARPG项目的需求:需要将现有的服务器从C++的编写平台换为java语言.在对需求进行分析的过程中,发现几点需要研究实现的问题 java与c+语言特性迥异,相比c+ 和c#关系的密切性,java需要对c#风格的一些数据结构和编码格式进行兼容: c#拥有的无符号数据类型如 ushort unint java并不存在,需要对数据类型进行转换: 根据开发需要 客户端现有的通信协议不能更改,所以在java中进行各类型的兼容操作 在项目中底层通信

Socket编程——怎么实现一个服务器多个客户端之间的连接

  1 package coreBookSocket; 2 3 import java.io.IOException; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 7 /* 8 * 这个方法的主要目地是为了用多线程的方法实现网络编程,让多个客户端可以同时连接到一个服务器 9 *1:准备工作和单个客户端编程类似,先建立服务器端的套接字,同时让客户端那边调用accept()方法来接受服务器端的信息 10 *2:这里面定一个w

Thrift操作(Python服务端和Nodejs客户端)

目录 前言 python服务端 nodejs客户端 win10运行thrift 测试 前言 操作系统win10 时间2019年02月 Thrift版本:Thrift version 0.11.0 Python版本: Python 3.5.2 Nodejs版本: node v8.9.3 参考网址1 python服务端 安装thrift python install thrift server.py # -*- coding: utf-8 -*- import json # 调用python安装的t

Java Socket实现基于TCP和UDP多线程通信

一.通过Socket实现TCP编程 1.1 TCP编程 TCP协议是面向连接,可靠的,有序的,以字节流的方式发送数据.基于TCP协议实现网络通信的类有客户端的Socket类和服务器端的ServerSocket类. 1.2 服务器端套路 1.创建ServerSocket对象,绑定监听端口. 2.通过accept()方法监听客户端请求. 3.连接建立后,通过输入流读取客户端发送的请求信息. 4.通过输出流向客户端发送响应信息. 5.关闭响应的资源. 1.3 客户端套路 1.创建Socket对象,指明

跨平台通信中间件thrift学习【Java版本】(转)

转自:http://neoremind.com/2012/03/%E8%B7%A8%E5%B9%B3%E5%8F%B0%E9%80%9A%E4%BF%A1%E4%B8%AD%E9%97%B4%E4%BB%B6thrift%E5%AD%A6%E4%B9%A0%E3%80%90java%E7%89%88%E6%9C%AC%E3%80%91/ 1. What is thrift? Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目.跨平台

Thrift入门及Java实例演示&lt;转载备用&gt;

Thrift入门及Java实例演示 作者: Michael 日期: 2012 年 6 月 14 日 •概述 •下载配置 •基本概念 1.数据类型 2.服务端编码基本步骤 3.客户端编码基本步骤 4.数据传输协议 •实例演示(java) 1. thrift生成代码 2. 实现接口Iface 3.TSimpleServer服务模型 4.TThreadPoolServer 服务模型 5.TNonblockingServer 服务模型 6.THsHaServer服务模型 7.异步客户端 [一].概述 T

Java服务器对外提供接口以及Android端向服务器请求数据

讲解下java服务器是如何对移动终端提供接口的,以什么数据格式提供出去,移动端又是怎么请求服务器,接收以及解析返回数据的. 服务端:还是在原先S2SH框架的项目上(搭建SSH详细步骤及其相关说明),加入Servlet来做对终端提供接口的事情. Android端:用了一个网络访问框架okHttp,向服务器请求数据. 服务端: servlet接收移动端的get.post请求,进行相应逻辑处理后将要返回的数据封装成json格式写出去. 对数据库的操作传统的Servlet是用jdbc,但是操作过于繁琐,

java服务器集群高并发场景下发布导致load高的解决方案

我们的java服务器集群在发布的时候,会出现刚发布的服务器load飙高(超过cpu核数)的问题,过几分钟才能回到低位,分析了好久也没发现什么原因. 经过查阅相关资料,我们意识到jvm在刚启动时,性能并不是最好的状态,在随后的运行过程中,它会自动分析热点(运行频率高的的代码),并对热点代码进行优化,所以jvm运行一段时间后才能获得较好的性能.这个问题在体量较小的应用中无法体现,当qps达到较高水平时,才会出现这个问题. 但网上查到的资料也就到这里了,并没有给出解决方案.于是综合自己的思考,以及与某