0%

【Linux技术分享】利用thrift实现跨语言通讯

blog的搭建

利用thrift的跨平台机制实现进程通讯,本机是uos系统+go语言,virtualbox是windows系统+C++,在virtualbox上增加端口转发既可实现windows与uos两者不同系统不同语言的进程通讯。

thrift简介

1. 理论知识

Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。它通过一个代码生成引擎联合了一个软件栈,来创建不同程度的、无缝的跨平台高效服务,可以使用C#、C++(基于POSIX兼容系统)、Cappuccino、Cocoa、Delphi、Erlang、Go、Haskell、Java、Node.js、OCaml、Perl、PHP、Python、Ruby和Smalltalk。虽然它以前是由Facebook开发的,但它现在是Apache软件基金会的开源项目了。该实现被描述在2007年4月的一篇由Facebook发表的技术论文中,该论文现由Apache掌管。

2.注意事项

  1. Thrift支持的基本数据类型
    • byte: 有符号字节
    • i16: 16 位有符号整数
    • i32 : 32 位有符号整数
    • i64: 64 位有符号整数
    • double : 64 位浮点数
    • string : 字符串
  2. 可用容器类型
    • list(t): 元素类型为t的有序表,容许元素重复。
    • set(t):元素类型为t的无序表,不容许元素重复。对应c++中的set,java中的HashSet,python中的set,php中没有set,则转换为list类型。
    • map(t,t): 键类型为t,值类型为t的kv对,键不容许重复。对用c++中的map, Java的HashMap, PHP 对应 array, Python/Ruby 的dictionary。
  1. Thrift 架构(图来自于网络)
    thrift主要用于各个服务之间的RPC通信,支持跨语言。thrift是一个典型的CS结构,客户端和服务端可以使用不同的语言开发,thrift通过IDL(Interface Description Language)来关联客户端和服务端。thrift的整体架构图如下图所示
    图1

uos利用go实现thrift的客户端和服务端

  1. goland安装thrift包

    go get git.apache.org/thrift.git/lib/go/thrift
    调用命令thrift -version显示版本号即安装成功。

  2. 下载的文件加入到gopath

  3. 编写属于接口的fuse.thrift的LDL文件,我本地要实现一个剪切板数据互发功能,所以接口为剪切板功能。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    namespace go fuse
    service WindowsToUos {
    //windows 剪切板发送到uos
    bool sendCliboard(1:i32 nType, 2:string path);
    void stop();
    }

    service UosToWindows{
    //uos 剪切板发送到windows
    bool sendCliboard(1:i32 nType, 2:string path, 3:string Vol);
    }

    在service windowstouos中,是windows为客户端,uos为服务端。在uostowindows中,是windows为服务端,uos为客户端。两者可以来回通讯。

  4. 运行命令,生成相关代码,目录下就会存在一个gen-go的一个代码文件夹

    thrift -r –gen go fuse.thrift

  5. 服务端接口初始化代码如下,EchoServerImp接口为空接口。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
      type EchoServerImp struct {
    }

    func (s *Server) ServerStart(port int) {
    protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
    transportFactory := thrift.NewTBufferedTransportFactory(10000000)
    serverTransport, err := thrift.NewTServerSocket("127.0.0.1:9150")
    if err != nil {
    fmt.Println("Error!", err)
    os.Exit(1)
    }

    handler := &EchoServerImp{}
    processor := fuse.NewWindowsToUosProcessor(handler)
    server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
    fmt.Println("thrift server in", "127.0.0.1:9150")
    server.Serve()
    }

    func main() {
    go func() {
    // ListenClipboard()
    }()
    ctxT, cancelFunc = context.WithCancel(context.Background())
    sev := &Server{}
    sev.ServerStart(8192)
    }
  6. 在服务端时,需要把LDL的函数实现,不然会报错,逻辑实现代码如下

    1
    2
    3
    4
    5
      func (e *EchoServerImp) Stop(ctx context.Context) error {
    logger.Info("Revice Stop!!!")
    stop()
    return nil
    }
  7. 客户端接口初始化代码如下。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33

    type Manager struct {
    clipboard // interface com.deepin.ListenClipboard
    proxy.Object
    }

    type ClipboardService struct {
    loginManager *Manager
    sessionSigLoop *dbusutil.SignalLoop
    service *dbusutil.Service
    }

    func ListenClipboard() error {
    var cb ClipboardService
    //注册剪切板dbus信号
    sessionBus, err := dbus.SessionBus()
    if err != nil {
    logger.Warning("failed to register clipboard changed signal:", err)
    return err
    }
    cb.loginManager = NewCBManager(sessionBus)
    cb.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10)
    cb.sessionSigLoop.Start()
    cb.loginManager.InitSignalExt(cb.sessionSigLoop, true)

    //绑定剪切板变化dbus信号
    //_, err = cb.loginManager.ConnectClipboardChange()qqq+
    if err != nil {
    logger.Warning("failed to connect clipboard changed signal:", err)
    return err
    }
    return nil
    }
  8. 客户端调用服务端代码如下

    1
    cb.loginManager.SendCliboardToWindows(clipboardType, clipboardData, vol)

windows利用C++实现thrift的客户端和服务端

利用virtualbox的端口转发机制,实现windows和uos互相通讯