介绍
这篇文章主要介绍如何使用 Protobuf 来在 Go 语言程序和 C++ 程序之间进行数据交互。
这里使用 Go 编写服务端,而用 C++ 编写客户端。
编写 proto 协议文件
在开始写客户端和服务端之前,首先需要生成 Go 和 C++ 的 proto 协议文件,只编写一个 proto 文件即可。
新建一个名为 msg.proto
的文件,输入如下内容:
syntax = "proto3";
package msg;
message Msg {
int64 MsgId = 1;
string MsgInfo = 2;
string MsgFrom = 3;
}
编译 proto 文件
执行下列命令分别生成 Go 语言和 C++ 对应的文件
protoc --cpp_out=. msg.proto
protoc --go_out=. msg.proto
编写 Go 服务端程序
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++ 客户端程序
#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;
}
运行
先后启动服务端和客户端程序