Protobuf簡介
ProtoBuf在網絡通信、通用數據交換等場景的效率、兼容性等方面非常出色。
介紹
protocol buffers 是一種語言無關、平臺無關、可擴展的序列化結構數據的方法,它可用於(數據)通信協議、數據存儲等。支持 Java、C++、Python 等多種語言,支持多個平臺。
你可以定義數據的結構,然後使用特殊生成的源代碼輕鬆的在各種數據流中使用各種語言進行編寫和讀取結構數據。你甚至可以更新數據結構,而不破壞由舊數據結構編譯的已部署程序。
特點
序列化將結構數據或對象轉換成能夠被存儲和傳輸(例如網絡傳輸)的格式,同時應當要保證這個序列化結果在之後(可能在另一個計算環境中)能夠被重建回原來的結構數據或對象。可以更新數據結構,而不影響和破壞原有的舊程序
Protobuf編譯
- 下載Protobuf
https://github.com/google/protobuf/releases
- 下載並安裝CMake
https://cmake.org/download/
- 編譯Protobuf
1、打開CMake,點擊下圖1 按鈕選擇解壓出來的protobuf包位置下的cmake文件夾(xxx\protobuf-3.9.2\cmake)。
2、接着點擊下圖2 按鈕選擇編譯生成目錄。
3、接着點擊下圖3 編譯
4、接着點擊下圖4 生成
- 產生庫
使用CMake第二步選擇的Vs版本軟件打開編譯出來的工程ALL_BUILD.vcxproj。 或直接點擊CMake軟件"Open Project"按鈕。
如下圖,只進行編譯紅色線框選的工程。
這裏作者選擇生成了x64下degbu和release:
把protobuf-3.6.1\src\google\protobuf這個目錄中的頭文件(其餘的文件可以刪除,也可以保留,不影響),都拷貝出來後面使用。
Protobuf使用
1、創建.proto文件、.bat文件
完成如上圖編輯後,將protocd.exe(debug版)拷貝到同目錄下,雙擊.bat文件運行得到.pb.cc、.pb.h兩個文件。
2、 創建測試 (Vs2015+Qt5.12.4)
測試過程:創建兩個Vs+Qt工程分別爲A和B,使用上述proto文件定義的內容並序列化後以Udp單播在程序A和程序B中通信並顯示。
(1)、創建A和B工程
(2)、創建相同的A(5566)、B(7788)程序界面
(3)、配置Protobuf
①將.pb.cc、.pb.h拷貝到代碼位置並添加到工程內。②將之前編譯的lib和頭文件,拷貝到工程目錄裏面,將頭文件引用、將庫文件加入工程。(加入辦法自行百度)
(4)、編寫序列化並udp傳輸
// 發送端
void ProtobufTest_A::on_sendButton_A_clicked()
{
// 單播
// qint64 len = mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(),QHostAddress("192.168.137.1"),6677);
//組播ip地址範圍:224.0.0.0-239.255.255.255
//qint64 len = mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(),QHostAddress("224.0.0.100"),6677);
//廣播
//qint64 len = mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(), QHostAddress::Broadcast, 6677);
// 序列化前初始值 (注意:std::string 必須轉爲utf8,否則異常)
tutorial::ProtobufTest protobufTest;
protobufTest.set_id(ui.port_A->text().toInt());
protobufTest.set_name(ui.ip_A->text().toUtf8().data());
protobufTest.set_email(ui.sendTxt_A->text().toUtf8().data());
// 獲取長度
unsigned short protobufTestLength = protobufTest.ByteSize() + 1;
// 存儲序列化buf
char *buf = nullptr;
buf = new char[protobufTestLength];
memset(buf, 0, protobufTestLength);
// 序列化
protobufTest.SerializeToArray(buf, protobufTestLength);
// udp發送(UdpSocket_A爲QUdpSocket)
UdpSocket_A->writeDatagram(buf, protobufTestLength, QHostAddress(ip_B), port_B);
// 釋放序列化buf
if (buf)
delete buf;
buf = nullptr;
}
// 接收端
void ProtobufTest_A::readyRead()
{
QByteArray array;
// UdpSocket_A爲QUdpSocket
array.resize(UdpSocket_A->bytesAvailable());
if (array.size())
{
// 接收消息
UdpSocket_A->readDatagram(array.data(), array.size());
tutorial::ProtobufTest protobufTest;
// 反序列化
protobufTest.ParseFromArray(array.data(), array.size());
// 顯示
ui.receiveTxt_A->append("id:\t" + QString::number(protobufTest.id()));
ui.receiveTxt_A->append("name:\t" + QString(protobufTest.name().c_str()));
ui.receiveTxt_A->append("email:\t" + QString(protobufTest.email().c_str()) + '\n');
}
}
(5)、查看結果
源碼
關注
微信公衆號搜索"Qt_io_"或"Qt開發者中心"瞭解更多關於Qt、C++開發知識.。
筆者 - jxd