使用protobuf c實現TCP網路資料傳輸
阿新 • • 發佈:2020-12-10
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