>

介绍

这篇文章主要介绍如何使用 Protobuf 来在 Go 语言程序和 C++ 程序之间进行数据交互。

这里使用 Go 编写服务端,而用 C++ 编写客户端。

编写 proto 协议文件

在开始写客户端和服务端之前,首先需要生成 Go 和 C++ 的 proto 协议文件,只写了一个 proto 文件即可
新建一个名为 msg 的 proto 文件,输入如下内容:

1
2
3
4
5
6
7
8
syntax = "proto3";
package msg;

message Msg {
int64 MsgId = 1;
string MsgInfo = 2;
string MsgFrom = 3;
}

编译 proto 文件

执行下列命令分别生成 Go 语言和 C++ 对应的文件

1
2
protoc --cpp_out=. msg.proto
protoc --go_out=. msg.proto

编写 Go 服务端程序

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package main
import (
"fmt"
"os"
"net"

"test/msg"

"github.com/google/protobuf/proto"
)
func handleConn(conn net.Conn) {
defer conn.Close()
buf := make([]byte, 128)
n, err := conn.Read(buff)
if err != nil {
fmt.Println("read data failed...")
return
}
fmt.Printf("read len: %d\n", ReadLen)
fmt.Println(buff)

msgBuf := buf[0 : n]
reciveMsg := &msg.Msg {}

err = proto.Unmarshal(msgBuf, reciveMsg)
if err != nil {
fmt.Printf("unmarshaling error: ", reciveMsg)
}
fmt.Printf("msg id: %d\n", reciveMsg.GetMsgId())
fmt.Printf("msg info: %s\n", reciveMsg.GetMsgInfo())
fmt.Printf("msg from id: %s\n", reciveMsg.GetMsgFrom())
}

func main() {
tcpAddr, err := net.ResolveTCPAddr("tcp4", ":2121")
if err != nil {
fmt.Println("get tcp addr failed...")
return
}
listener, err := net.ListenTCP("tcp", tcpAddr)
if err != nil {
fmt.Println("listen tcp failed...")
return
}
for {
conn, err := listener.Accept()
if err != nil {
continue
}
go handleConn(conn)
}
}

编写 C++ 客户端程序

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
34
35
36
37
38
39
40
41
42
43
#include "msg.pb.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <string>

using namespace std;

int main(int argc, char *argv[]){

int sk = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(2121); // 固定端口port
server.sin_addr.s_addr = inet_addr("127.0.0.1"); // 固定ip

connect(sk, (struct sockaddr*)&server, sizeof(server));

msg::Msg sendMsg;
sendMsg.set_msgid(0);
sendMsg.set_msginfo("hello protobuf");
sendMsg.set_msgfrom("alex");

string sendData;
sendMsg.SerializeToString(&sendData);
int len = sendData.length();
cout << "string len:" << len << endl;

char *buff = new char[len + 1];
memcpy(buff, sendData.c_str(), len);

cout << "buff len:" << strlen(buff) << endl;
//向服务段发送数据
//在发送数据时一定要指明数据长度 防止中间有\0截断c风格字符串
send(sk, buff, len, 0);
close(sk);
return 0;
}

运行

先后启动服务端和客户端程序