Thrift RPC Java、Go、PHP使用例子

文章目录

    • 1、Thrift RPC介绍
      • 1.1、Protocol 支持的数据传输协议
      • 1.2、Transport 支持的数据传输方式
      • 1.3、Server 支持的服务模型
      • 1.4、IDL语法数据类型
      • 1.5、开发步骤
    • 2、接口定义文件
      • 2.1、创建接口定义文件
      • 2.2、生成对应平台语言代码
        • 2.2.1、下载生成工具
        • 2.2.2、生成各平台语言代码
    • 3、使用Java实现服务器端
    • 4、客户端实现
      • 4.1、Java调用客户端实现
      • 4.2、Go调用客户端实现
      • 4.3、PHP调用客户端实现

1、Thrift RPC介绍

Thrift 是一个软件框架(远程过程调用框架),用来进行可扩展且跨语言的服务的开发,封装了数据传输格式(二进制、json)和网络通信的服务框架,提供多语言(C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml)的网络服务器端和客户端程序组件
适用于搭建大型数据交换及存储的通用工具,对于大型系统中的内部数据传输相对于 JSON 和 xml 无论在性能、传输大小上有明显的优势。

Thrift 开发的几个概念:
Server 服务模型
Handler 数据处理接口
Processor 数据处理对象
Protocol 数据传输协议
Transport 数据传输方式

1.1、Protocol 支持的数据传输协议

  1. TBinaryProtocol – 二进制格式.
  2. TCompactProtocol – 压缩格式
  3. TJSONProtocol – JSON 格式
  4. TSimpleJSONProtocol –提供 JSON 只写协议,生成的文件很容易通过脚本语言解析。
  5. TDebugProtocol – 使用易懂的可读的文本格式,以便于 debug

1.2、Transport 支持的数据传输方式

  1. TFileTransport:文件(日志)传输类,允许 client 将文件传给 server,允许 server 将收到的数据写到文件中。
  2. THttpTransport:采用 Http 传输协议进行数据传输
  3. TSocket:采用 TCP Socket 进行数据传输
  4. TZlibTransport:压缩后对数据进行传输,或者将收到的数据解压

下面几个类主要是对上面几个类地装饰(采用了装饰模式),以提高传输效率。

TBufferedTransport:对某个 Transport 对象操作的数据进行 buffer,即从 buffer 中读取数据进行传输,或者将数据直接写入 buffer

TFramedTransport:以 frame 为单位进行传输,非阻塞式服务中使用。同 TBufferedTransport 类似,也会对相关数据进行 buffer,同时,它支持定长数据发送和接收。

TMemoryBuffer:从一个缓冲区中读写数据

1.3、Server 支持的服务模型

TSimpleServer – 简单的单线程服务模型,常用于测试
TThreadedServer - 多线程服务模型,使用阻塞式 IO,每个请求创建一个线程。
TThreadPoolServer – 线程池服务模型,使用标准的阻塞式 IO,预先创建一组线程处理请求。
TNonblockingServer – 多线程服务模型,使用非阻塞式 IO(需使用 TFramedTransport 数据传输方式)

处理大量更新的话,主要是在 TThreadedServer 和 TNonblockingServer 中进行选择。TNonblockingServer 能够使用少量线程处理大量并发连接,但是延迟较高;TThreadedServer 的延迟较低。实际中,TThreadedServer 的吞吐量可能会比 TNonblockingServer 高,但是 TThreadedServer 的 CPU 占用要比 TNonblockingServer 高很多。

1.4、IDL语法数据类型

  • 基本类型
bool:布尔值(true或false)
byte:8位有符号整数
i16:16位有符号整数
i32:32位有符号整数
i64:64位有符号整数
double:64位浮点数
string:使用UTF-8编码编码的文本字符串
  • 容器类型
list<t1>:一系列t1类型的元素组成的有序列表,元素可以重复
set<t1>:一些t1类型的元素组成的无序集合,元素唯一不重复
map<t1,t2>:key/value对,key唯一

1.5、开发步骤

服务器端开发:

1. 创建 Handler
2. 基于 Handler 创建 Processor
3. 创建 Transport(通信方式)
4. 创建 Protocol 方式(设定传输格式)
5. 基于 Processor, Transport 和 Protocol 创建 Server
6. 运行 Server

客户端开发:

1. 创建 Transport
2. 创建 Protocol 方式
3. 基于 Transport 和 Protocol 创建 Client
4. 运行 Client 的方法

2、接口定义文件

2.1、创建接口定义文件

test.thrift

/**
 * 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?
 */

// 命名空间,Java中的package
namespace java com.penngo.thrift
namespace php com.penngo
namespace go com.penngo

// 结构体
struct User {
	1: i64 id,
	2: string name,
	3: string password
}

// 服务,Java中创建Interface一样
service LoginService{
    // service中定义的函数,相当于Java interface中定义的函数
    User login(1:string name, 2:string psw);
}

service RegisterService{
    User createUser(1:string name, 2:string psw);
}

2.2、生成对应平台语言代码

2.2.1、下载生成工具

下载地址:https://thrift.apache.org/download
当前最新版本为:thrift-0.19.0.exe
thrift-0.19.0.exe重命名为thrift.exe,与test.thrift在同一目录。

2.2.2、生成各平台语言代码

执行以下命令分别生成Java、Go、PHP平台的代码

thrift -gen java test.thrift
thrift -gen go test.thrift
thrift -gen php:classmap test.thrift # 支持PSR-4 loader 
# thrift -gen php test.thrift

生成后的目录文件结构
在这里插入图片描述

3、使用Java实现服务器端

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.penngo</groupId>
    <artifactId>thrift-java</artifactId>
    <version>1.0</version>
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.thrift</groupId>
            <artifactId>libthrift</artifactId>
            <version>0.19.0</version>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.17.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.17.2</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.36</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>alimaven</id>
            <name>Maven Aliyun Mirror</name>
            <url>https://maven.aliyun.com/repository/central</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>https://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>

实现LoginService服务LoginServiceImpl.java

package com.penngo.service;

import com.penngo.thrift.LoginService;
import com.penngo.thrift.User;

public class LoginServiceImpl implements LoginService.Iface{
    public LoginServiceImpl(){
    }
    public User login(String name, String psw){
        User user = null;
        if(name.equals("penngo") && psw.equals("123")){
            user = new User();
            user.setId(1);
            user.setName("penngo");
        }
        return user;
    }
}

实现RegisterService服务RegisterServiceImpl.java

package com.penngo.service;
import com.penngo.thrift.RegisterService;
import com.penngo.thrift.User;

public class RegisterServiceImpl implements RegisterService.Iface{
    public RegisterServiceImpl(){
    }
    public User createUser(String name, String psw){
        User user = new User();
        user.setId(2);
        user.setName(name);
        user.setPassword(psw);
        return user;
    }
}

实现LoginService和RegisterService注册,完成服务启动。

package com.penngo;

import com.penngo.service.LoginServiceImpl;
import com.penngo.service.RegisterServiceImpl;
import com.penngo.thrift.LoginService;
import com.penngo.thrift.RegisterService;
import org.apache.thrift.TMultiplexedProcessor;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;

public class HelloServer {
    private void start() {
        try {
            TServerSocket serverTransport = new TServerSocket(7911);
            // 用户登录
            LoginService.Processor loginProcessor = new LoginService.Processor(
                    new LoginServiceImpl());
            // 用户注册
            RegisterService.Processor registerProcessor = new RegisterService.Processor(
                    new RegisterServiceImpl());
            TMultiplexedProcessor processor = new TMultiplexedProcessor();
            processor.registerProcessor("LoginService", loginProcessor);
            processor.registerProcessor("RegisterService", registerProcessor);
            TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(
                    serverTransport).processor(processor));
            System.out.println("Starting server on port 7911 ...");
            server.serve();
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) {
        HelloServer srv = new HelloServer();
        srv.start();
    }
}

项目文件结构
在这里插入图片描述

4、客户端实现

4.1、Java调用客户端实现

package com.penngo;

import com.penngo.thrift.LoginService;
import com.penngo.thrift.RegisterService;
import com.penngo.thrift.User;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TMultiplexedProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

public class HelloClient {
    public static void main(String[] args) {
        try {
            TTransport transport = new TSocket("localhost", 7911);
            TProtocol protocol = new TBinaryProtocol(transport);

            TMultiplexedProtocol mp1 = new TMultiplexedProtocol(protocol,
                    "LoginService");
            LoginService.Client loginClient = new LoginService.Client(mp1);
            TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol,
                    "RegisterService");
            RegisterService.Client registerClient = new RegisterService.Client(
                    mp2);
            transport.open();

            User user = loginClient.login("penngo", "123");
            if (user != null) {
                System.out.println("登录成功:" + user.getId() + " "
                        + user.getName());
            } else {
                System.out.println("登录失败");
            }

            User user2 = registerClient.createUser("test", "123456");
            if (user2 != null) {
                System.out.println("创建用户成功:" + user2.getId() + " "
                        + user2.getName());
            } else {
                System.out.println("创建用户失败");
            }
            transport.close();
        } catch (TException x) {
            x.printStackTrace();
        }
    }
}

4.2、Go调用客户端实现

安装Thrift依赖

go get github.com/apache/thrift

go客户端实现

package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"github.com/apache/thrift/lib/go/thrift"
	"net"
	"os"
	"thrifttest/com/penngo"
)

const (
	HOST = "127.0.0.1"
	PORT = "7911"
)

var ctx = context.Background()

func main() {
	cfg := &thrift.TConfiguration{
		TLSConfig: &tls.Config{
			InsecureSkipVerify: true,
		}}
	// 网络接口
	var transport thrift.TTransport
	var err error
	transport = thrift.NewTSocketConf(net.JoinHostPort(HOST, PORT), cfg)
	protocol := thrift.NewTBinaryProtocolConf(transport, cfg)

	// 客户端
	iprot := thrift.NewTMultiplexedProtocol(protocol, "LoginService")
	oprot := thrift.NewTMultiplexedProtocol(protocol, "LoginService")
	c := thrift.NewTStandardClient(iprot, oprot)
	loginClient := penngo.NewLoginServiceClient(c)

	// 客户端
	iprot2 := thrift.NewTMultiplexedProtocol(protocol, "RegisterService")
	oprot2 := thrift.NewTMultiplexedProtocol(protocol, "RegisterService")
	c2 := thrift.NewTStandardClient(iprot2, oprot2)
	registerClient := penngo.NewRegisterServiceClient(c2)

	if err := transport.Open(); err != nil {
		fmt.Fprintln(os.Stderr, "open transport error: ", err)
		os.Exit(1)
	}
	defer transport.Close()

	res, err := loginClient.Login(ctx, "penngo", "123")
	if err != nil {
		fmt.Fprintln(os.Stderr, "======error: ", err)
		os.Exit(1)
	}
	fmt.Fprintln(os.Stderr, "Login=====: ", res)

	res2, err2 := registerClient.CreateUser(ctx, "test", "123456")
	if err2 != nil {
		fmt.Fprintln(os.Stderr, "======error: ", err2)
		os.Exit(1)
	}
	fmt.Fprintln(os.Stderr, "CreateUser=====: ", res2)
}

项目文件结构
在这里插入图片描述

官方例子:https://thrift.apache.org/tutorial/go.html

4.3、PHP调用客户端实现

创建composer.json

{
  "require": {
    "apache/thrift": "^0.19.0"
  },
  "autoload": {
    "files": [
      "com/penngo/LoginService.php",
      "com/penngo/RegisterService.php",
      "com/penngo/Types.php"
    ]
  }
}

使用composer安装依赖

composer install

php客户端实现代码

<?php
require_once 'vendor/autoload.php';

use Thrift\Transport\TSocket;
use Thrift\Protocol\TBinaryProtocol;
use Thrift\Transport\TBufferedTransport;
use Thrift\Protocol\TMultiplexedProtocol;
use com\penngo\LoginServiceClient;
use com\penngo\RegisterServiceClient;

// 传输方式(需与服务端一致)
$socket = new TSocket("localhost", 7911);
// 传输协议(需与服务端一致)
$transport = new TBufferedTransport($socket, 1024, 1024);
$protocol = new TBinaryProtocol($transport);
$loginProtocol = new TMultiplexedProtocol($protocol, "LoginService");
$registerProtocol = new TMultiplexedProtocol($protocol, "RegisterService");
$loginClient = new LoginServiceClient($loginProtocol);
$registerClient = new RegisterServiceClient($registerProtocol);
$transport->open();
$user = $loginClient->login('penngo', '123');
print "login====".json_encode($user);

$user = $registerClient->createUser('test', '123456');
print "\ncreateUser====".json_encode($user);
$transport->close();

项目文件结构
在这里插入图片描述

php官方例子:https://thrift.apache.org/lib/php.html

附件源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/202072.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单片机----串行通信

目录 串行通信的两种方式 串行通信的传输模式 串行通信的错误校验 1.奇偶校验 2.代码和校验 3.循环冗余码校验 串行口结构 串行口控制寄存器SCON 特殊功能寄存器PCON 串行口的4种工作方式 方式0&#xff1a; &#xff08;1&#xff09;方式0的发送过程 &#xff0…

数据结构---堆

1.堆的概念及结构 堆的性质&#xff1a; 堆中某个节点的值总是不大于或不小于其父节点的值堆总是一棵完全二叉树 2.举例说明 堆一般是把数组数据看做是一棵完全二叉树 小堆要求&#xff1a;任意一个父亲<孩子大堆要求&#xff1a;任意一个父亲>孩子 比如&#xff1…

计算机图形学:直线的扫描转换算法解析与实现

直线的扫描转换&#xff1a; DDA算法&#xff1a; 推理&#xff1a; 在计算机显示图形时&#xff0c;由于显示计算机的分辨率是有限的所以我们在绘制图形时需要将图形从连续量转换成离散量才能完成图形的绘制&#xff0c;直线的扫描转换就是将连续量转换为离散量的过程。 对…

UE Web Remote Control

前言 最近在研究UE自启WEB服务和网页通信以此来通过网页与UE进行数据交互&#xff0c;这样最好的方式就是可以摒弃掉整个繁琐的通信连接流程如TCP UDP&#xff0c;但是找到的一些方法都不是很适用&#xff0c;尤其是WEBUI这个插件它只适合内嵌到UE本身才能完成交互&#xff0c;…

mybatis关于namespace以及id以及Mapper接口命名的说明(了解)

1、建库建表 CREATE DATABASE mybatis-example;USE mybatis-example;CREATE TABLE t_emp(emp_id INT AUTO_INCREMENT,emp_name CHAR(100),emp_salary DOUBLE(10,5),PRIMARY KEY(emp_id) );INSERT INTO t_emp(emp_name,emp_salary) VALUES("tom",200.33); INSERT INTO…

Pytorch从零开始实战11

Pytorch从零开始实战——ResNet-50V2算法实战 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——ResNet-50V2算法实战环境准备数据集模型选择开始训练可视化总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pyt…

CentOS 8 安装国内、本地YUM源

环境&#xff1a;windows 11、 VMware 17、Cent OS 8 目的&#xff1a;加快软件下载速度 1、国内YUM源安装 使用国外的源&#xff0c;速度卡到不显示 备份默认YUM源文件 [rootlocalhost ~]# cd /etc/yum.repos.d/ [rootlocalhost yum.repos.d]# mkdir yum.bak [rootlocalho…

Drawer抽屉(antd-design组件库)简单用法

1.Drawer抽屉 屏幕边缘滑出的浮层面板。 2.何时使用 抽屉从父窗体边缘滑入&#xff0c;覆盖住部分父窗体内容。用户在抽屉内操作时不必离开当前任务&#xff0c;操作完成后&#xff0c;可以平滑地回到原任务。 需要一个附加的面板来控制父窗体内容&#xff0c;这个面板在需要时…

3D场景建模工具

在线工具推荐&#xff1a; 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数据生成器 - 3D模型在线转换 - 3D模型预览图生成服务 1. 什么是3D场景建模&#xff1f; 3D场景建模是一种通过计算机图形学技术&#xff0c;将现实世…

<Linux>冯诺依曼体系结构||操作系统||系统调用于用户操作接口

前言:本文从软硬件角度计算机解释软硬件结构 硬件—冯诺依曼体系结构 软件—操作系统 文章目录 冯诺依曼计算机体系结构背景理解举例 操作系统(OS)OS的管理为什么要有操作系统? 系统调用与用户操作接口系统调用用户操作接口引入:printf&&scanf的重新理解库函数 计算机…

Could NOT find resource [logback-test.xml]

修改 之后就可以正常启动了

Node.js案例 - 记账本

目录 项目效果 项目的搭建 ​编辑 响应静态网页 ​编辑 ​编辑 结合MongoDB数据库 结合API接口 进行会话控制 项目效果 该案例实现账单的添加删除查看&#xff0c;用户的登录注册。功能比较简单&#xff0c;但是案例主要是使用前段时间学习的知识进行实现的&#xff0c…

详解原生Spring当中的额外功能开发MethodBeforeAdvice与MethodInterceptor接口!

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…

软件测试测试文档的编写和阅读

在软件测试中的流程中&#xff0c;测试文档也是一个重要的流程&#xff0c;所以测试人员也需要学习测试文档的编写和阅读。 一、定义&#xff1a; 测试文档&#xff08;Testing Documentation&#xff09;记录和描述了整个测试流程&#xff0c;它是整个测试活动中非常重要的文…

layui提示框没有渲染bug解决

bug&#xff1a;使用layui时或许是依赖导入又或是ideal和浏览器缓存问题导致前面明明正常的页面显示&#xff0c;后面出现提示框没有css样式&#xff0c;弹出框没有背景css 效果如下 解决后 解决方法 在你的代码中引入layer.js 我这是jsp页面 <script type"text/jav…

idea方法注释模版设置

方法上面的注释模版&#xff1a; Template text: ** Description $desc$ $param$ $return$* Aauthor yimeng* date $DATE$ $TIME$ **/param&#xff1a; groovyScript("def result ;def params \"${_1}\".replaceAll([\\\\[|\\\\]|\\\\s], ).split(,).toLis…

机器学习笔记 - 3D数据的常见表示方式

一、简述 从单一角度而自动合成3D数据是人类视觉和大脑的基本功能,这对计算机视觉算法来说是比较难的。但随着LiDAR、RGB-D 相机(RealSense、Kinect)和3D扫描仪等3D传感器的普及和价格的降低,3D 采集技术的最新进展取得了巨大飞跃。与广泛使用的 2D 数据不同,3D 数据具有丰…

Opencv 极坐标变换

变换后图片 代码 // 以Center为极坐标原点&#xff0c;将RowFrom到RowTo的圆环&#xff0c;仅仅变换该范围内的点&#xff0c;忽略掉其他部分。 #include "polar_transeforme.hpp" #include <string>using namespace cv;void calculate_map(int rouFrom, int …

Matlab 在一个文件中调用另一个文件中的函数

文章目录 Part.I IntroductionPart.II 方法Chap.I A 文件中只有一个函数Chap.II A 文件中有多个函数 Part.I Introduction 本文介绍一下在脚本文件 B 中调用文件 A 中的函数的方法。 Part.II 方法 目的&#xff1a;在文件B.m调用A.m中的函数 默认两个文件在一个文件夹下&…

JSch线上出现com.jcraft.jsch.JSchException: channel is not opened.问题分析

JSch线上出现com.jcraft.jsch.JSchException: channel is not opened.问题分析 文章目录 JSch线上出现com.jcraft.jsch.JSchException: channel is not opened.问题分析1. 背景1.系统使用jsch这个框架做文件发送以及远程命令执行的操作,系统一直运行正常,直到某一个环境发现 2.…