1. 自定义数据字段类型:
enum UserStatus {
UNKNOWN = 0;
IDLE = 1;
BUSY = 2;
}
message UserInfo {
required string name = 1;
required uint32 age = 2;
optional string phone = 3;
required UserStatus stat = 4;
optional string email = 5;
}
2. 生成.c 和.h文件:
protoc-c --c_out=./ UserInfo.proto
3. 编写服务器端代码:
#include "UserInfo.pb-c.h"
#include <stdio.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
struct msg_proto_header
{
uint8_t version;
uint16_t command;
uint32_t length;
};
enum MSG_COMMOND
{
LOGIN_REQUEST,
};
int main()
{
int fd = socket(AF_INET,SOCK_STREAM,0);
if(fd < 0)
return -1;
struct sockaddr_in local_addr = {0};
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(9999);
local_addr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(fd,(struct sockaddr *)&local_addr, sizeof(local_addr));
if(ret < 0)
return -1;
listen(fd, 5);
struct sockaddr_in client_addr = {0};
int len = sizeof(client_addr);
int clientfd = accept(fd,(struct sockaddr *)&client_addr, &len);
if(clientfd < 0)
return -1;
int read_size = 0;
char buf[1024];
struct msg_proto_header header;
while(1)
{
memset(&header, 0, sizeof(struct msg_proto_header));
memset(buf, 0, 1024);
read_size = recv(clientfd, &header, sizeof(struct msg_proto_header), 0);
if(read_size < 0){
perror("recv fail:");
break;
}
if(header.command == LOGIN_REQUEST && header.length > 0)
{
read_size = recv(clientfd, buf, header.length, 0);
if(read_size < 0){
perror("recv fail:");
break;
}
UserInfo * userInfo = user_info__unpack(NULL, header.length, buf);
if(!userInfo){
printf("user_information__unpack is fail!\n");
continue;
}
printf("Unpack: %s %d %d\n", userInfo->name, userInfo->age, userInfo->stat);
user_info__free_unpacked(userInfo, NULL);
}
}
close(fd);
return 0;
}
4. 编写客户端代码:
#include "UserInfo.pb-c.h"
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
struct msg_proto_header
{
uint8_t version;
uint16_t command;
uint32_t length;
};
enum MSG_COMMOND
{
LOGIN_REQUEST,
};
int main()
{
int fd = socket(AF_INET,SOCK_STREAM,0);
if(fd < 0)
return -1;
struct sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(9999);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(ret < 0)
{
printf("connect fail!\n");
return -1;
}
uint8_t buffer[1024] = {0};
UserInfo user;
user_info__init(&user);
user.name = "dabai";
user.age = 18;
user.stat = USER_STATUS__IDLE;
size_t length = user_info__pack(&user, buffer);
struct msg_proto_header msg_header;
msg_header.version = 0x01;
msg_header.command = LOGIN_REQUEST;
msg_header.length = length;
//每隔5s发送一次数据包
while(1)
{
send(fd, &msg_header, sizeof(struct msg_proto_header), 0);
send(fd, buffer, length, 0);
sleep(5);
}
close(fd);
return 0;
}
5. 验证结果:
启动server: ./server
启动client: ./client
观察server 效果:
Unpack: dabai 18 1
Unpack: dabai 18 1