Protocol Buffers(protobuf)是一种由Google开发的用于序列化结构化数据的方法,通常用于在不同应用程序之间进行数据交换或存储数据。它是一种语言无关、平台无关、可扩展的机制,可以用于各种编程语言和环境中。
1、首先建立proto文件,syntax如果不标明proto3,则会默认使用proto2版本,在后面的使用过程中需要加上包名,以防止命名空间冲突,消息体中的序号表明在序列化数据中该变量出现的顺序。如果要规定该变量只有n中可能,可以使用枚举类型,例如表示人的性别男女。编辑 protoc -I=. --cpp_out=. message.proto
protobuf3文档中文译版
cpp
syntax = "proto3";
package csj;
message MyMessage {
int32 id = 1;
string content = 2;
}
2、编写服务端,编辑 g++ -o server server.cpp message.pb.cc -lprotobuf
cpp
#include "message.pb.h" // 你的protobuf生成的头文件
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
using namespace std;
// 接收protobuf消息
bool ReceiveProtobufMessage(int socket_fd, csj::MyMessage* message) {
std::string serialized_message;
const int BUFFER_SIZE = 1024; // 设置一个缓冲区大小
char buffer[BUFFER_SIZE];
ssize_t received = recv(socket_fd, buffer, BUFFER_SIZE, 0);
if (received < 0) {
std::cerr << "Failed to receive message." << std::endl;
return false;
}
serialized_message.assign(buffer, received);
if (!message->ParseFromString(serialized_message)) {
std::cerr << "Failed to parse received message." << std::endl;
return false;
}
return true;
}
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len;
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
cerr<<"Error opening socket"<<endl;
return 1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(12346);
if (bind(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
cerr<<"Error on binding"<<endl;
return 1;
}
if (listen(server_fd, 5) < 0) {
cerr<<"Error on listen"<<endl;
return 1;
}
// std::cout << "Server listening on port " << PORT << std::endl;
client_len = sizeof(client_addr);
client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_len);
if (client_fd < 0) {
cerr<<"Error on accept"<<endl;
return 1;
}
// 假设socket_fd是已经建立的socket连接的文件描述符
while(true)
{
csj::MyMessage message;
if (!ReceiveProtobufMessage(client_fd, &message)) {
std::cerr << "Failed to receive protobuf message." << std::endl;
return 1;
}
std::cout << "Received message: " << message.id() << ", " << message.content() << std::endl;
}
close(client_fd);
close(server_fd);
return 0;
}
3、编写客户端,编辑 g++ -o client client.cpp message.pb.cc -lprotobuf
cpp
#include "message.pb.h" // 你的protobuf生成的头文件
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
using namespace std;
// 发送protobuf消息
bool SendProtobufMessage(int socket_fd, const csj::MyMessage& message) {
std::string serialized_message;
if (!message.SerializeToString(&serialized_message)) {
std::cerr << "Failed to serialize message." << std::endl;
return false;
}
ssize_t sent = send(socket_fd, serialized_message.data(), serialized_message.size(), 0);
if (sent < 0) {
std::cerr << "Failed to send message." << std::endl;
return false;
}
return true;
}
int main() {
int clientSocket;
struct sockaddr_in serverAddress;
// 创建套接字
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
cerr << "Failed to create socket" << endl;
return -1;
}
// 设置服务器地址和端口
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddress.sin_port = htons(12346);
// 连接服务器
if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
cerr << "Failed to connect to server" << endl;
return -1;
}
// 假设socket_fd是已经建立的socket连接的文件描述符
while(true)
{
csj::MyMessage message;
cout<<"please enter id:";
int id;
cin>>id;
cout<<"please enter content:";
string content;
cin>>content;
message.set_id(id);
message.set_content(content);
if (!SendProtobufMessage(clientSocket, message))
{
std::cerr << "Failed to send protobuf message." << std::endl;
return 1;
}
}
close(clientSocket);
return 0;
}
当服务端两次使用同一个端口号,会出现Error on binding,这是同一时间在同一端口上启动两个TCP服务器,第二个服务器会收到端口已被占用的错误,并且无法绑定到该端口上。这是因为操作系统会阻止多个应用程序同时绑定到相同的端口上,以确保网络通信的正确性和稳定性。虽然服务端结束了,但这个接口不会立马就"让"出来,而是过一段时间由OS自动释放