编写数据通信协议代码的小技巧
1.有时候我们需要制定协议与其他设备、后台服务器通信,为了代码后期的易维护性,就不用以下这种方式,因为如果没有协议文档对照这里面代码就给人感觉有点魔幻。
char send_data[64]={0}; send_data[0]=0x49; send_data[1]=0x52; .... send_data[63]=0x52; //或者这样,这样子在修改协议代码还好改一点,但脱离了协议,比较难理解这些赋值的实际含义 int index=0; send_data[index]=0x49; send_data[index++]=0x52; index+=2; char flag=0x53; send_data[index]=flag; .... send_data[index]=0x52;
有时候还需要小端转大端,上传服务器,如果用这种方法赋值,没有协议文档接手这份代码的人就有点疑惑。实际上,上面的方法运行的速度是最快的,但就是不便维护。
2.我们可以将协议头、数据、协议尾分开定义,方便后期协议修改,代码作少量改动。
如果协议允许,可以尝试字节对齐,如4字节对齐、8字节对齐,即short byte等都用对齐占4字节,牺牲性能换取代码的易维护性。
这里就用简单的办法实现,较为容易维护代码,但代码比较冗余,实现转换为大端字节通信。
V1:
myprotocol.h
#ifndef _MYPROTOCOL_H_ #define _MYPROTOCOL_H_ #ifdef __cplusplus extern "C" { #endif typedef struct _my_msg_head { char msg_head[2]; char version[2]; char msg_num[4]; char reply_num[4]; char utc_time[8]; char data_len[4]; }my_msg_head; typedef struct _my_msg_data { char role_id[8]; char move_type[4]; char distance[4]; char speed[2]; }my_msg_data; typedef struct _my_msg_tail { char msg_tail[2]; }my_msg_tail; //大端字节序列 void set_short_value_b(char* out,short in);//2 void set_int_value_b(char* out,int in);//4 void set_float_value_b(char* out,float in);//4 void set_double_value_b(char* out,double in);//8 void set_long_long_value_b(char* out,long long in);//8 void set_ushort_value_b(char* out,unsigned short in);//2 void set_uint_value_b(char* out,unsigned int in);//4 void set_ulong_long_value_b(char* out,unsigned long long in);//8 int make_frame_data(my_msg_head *,my_msg_data*,my_msg_tail*,char *in,int in_size); #ifdef __cplusplus } #endif #endif
myprotocol.c
#include <stdio.h> #include <string.h> #include "myprotocol.h" void set_short_value_b(char* out,short in) { out[0]=(char)((in>>8)&0xff); out[1]=(char)(in&0xff); } void set_int_value_b(char* out,int in) { out[0]=(char)((in>>24)&0xff); out[1]=(char)((in>>16)&0xff); out[2]=(char)((in>>8)&0xff); out[3]=(char)(in&0xff); } void set_float_value_b(char* out,float in) { char *p=(char*)(&in); for(int i=0;i<4;i++) { out[i]=p[4-i-1]; } } void set_double_value_b(char* out,double in) { char *p=(char*)(&in); for(int i=0;i<8;i++) { out[i]=p[8-i-1]; } } void set_long_long_value_b(char* out,long long in) { char *p=(char*)(&in); for(int i=0;i<8;i++) { out[i]=p[8-i-1]; } } void set_ushort_value_b(char* out,unsigned short in) { char *p=(char*)(&in); for(int i=0;i<2;i++) { out[i]=p[2-i-1]; } } void set_uint_value_b(char* out,unsigned int in) { char *p=(char*)(&in); for(int i=0;i<4;i++) { out[i]=p[4-i-1]; } } void set_ulong_long_value_b(char* out,unsigned long long in) { char *p=(char*)(&in); for(int i=0;i<8;i++) { out[i]=p[8-i-1]; } } int make_frame_data(my_msg_head *p_head,my_msg_data* p_data,my_msg_tail* p_tail,char *in,int in_size) { int head_len=sizeof(my_msg_head); int data_len=sizeof(my_msg_data); int tail_len=sizeof(my_msg_tail); int total_len=head_len+ data_len+tail_len; if(in_size<total_len) { return -1; } memcpy(in,p_head,head_len); memcpy(in+head_len,p_data,data_len); memcpy(in+head_len+data_len,p_tail,tail_len); return total_len; }
main.c
#include <stdio.h> #include <time.h> #include <unistd.h> #include <string.h> #include "myprotocol.h" void printData(char *data,int len) { printf("data :\n"); for(int i=0;i<len;i++) { printf("%02x ",(unsigned char)data[i]); if(i>0&&((i+1)%10==0)) { printf("\n"); } } printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); } unsigned long long getTime_ms() { struct timespec time1 = {0, 0}; clock_gettime(CLOCK_REALTIME, &time1); unsigned long long ret=((unsigned long long)time1.tv_sec)*1000+((unsigned long long)time1.tv_nsec)/1000/1000+8*60*60*1000; printData((char *)&ret,8); return ret; } int main(int argc, char **argv) { char send_data[512]={0}; my_msg_head m_head; my_msg_data m_data; my_msg_tail m_tail; memset(&m_head,0,sizeof(m_head)); memset(&m_data,0,sizeof(m_data)); memset(&m_tail,0,sizeof(m_tail)); m_head.msg_head[0]=0x05; m_head.msg_head[1]=0x49; m_head.version[1]=0x01; m_head.version[0]=0x00; set_int_value_b(m_head.msg_num,0x1002); set_int_value_b(m_head.reply_num,0x20001); set_ulong_long_value_b(m_head.utc_time,getTime_ms()); set_int_value_b(m_head.data_len,sizeof(my_msg_data)); set_ulong_long_value_b(m_data.role_id,0x1234); set_uint_value_b(m_data.move_type,(unsigned int)0x56789); set_uint_value_b(m_data.distance,0x1234); set_ushort_value_b(m_data.speed,0x5678); m_tail.msg_tail[0]=0x05; m_tail.msg_tail[1]=0x49; int send_len=make_frame_data(&m_head,&m_data,&m_tail,send_data,sizeof(send_data)); printData(send_data,send_len); /* 小端: 49 05 01 00 02 10 00 00 01 00 02 00 b6 04 9f b0 76 01 00 00 12 00 00 00 34 12 00 00 00 00 00 00 89 67 05 00 34 12 00 00 78 56 49 05 大端: 05 49 00 01 00 00 10 02 00 02 00 01 00 00 01 76 b0 9f 04 b6 00 00 00 12 00 00 00 00 00 00 12 34 00 05 67 89 00 00 12 34 56 78 05 49 */ }
V2
加入了字节长度判断,代码更加冗余了
myprotocol.h
#ifndef _MYPROTOCOL_H_ #define _MYPROTOCOL_H_ #ifdef __cplusplus extern "C" { #endif typedef struct _my_msg_head { char msg_head[2]; char version[2]; char msg_num[4]; char reply_num[4]; char utc_time[8]; char data_len[4]; }my_msg_head; typedef struct _my_msg_data { char role_id[8]; char move_type[4]; char distance[4]; char speed[2]; }my_msg_data; typedef struct _my_msg_tail { char msg_tail[2]; }my_msg_tail; //大端字节序列 void set_short_value_b(char* out,short in,int len);//2 void set_int_value_b(char* out,int in,int len);//4 void set_float_value_b(char* out,float in,int len);//4 void set_double_value_b(char* out,double in,int len);//8 void set_long_long_value_b(char* out,long long in,int len);//8 void set_ushort_value_b(char* out,unsigned short in,int len);//2 void set_uint_value_b(char* out,unsigned int in,int len);//4 void set_ulong_long_value_b(char* out,unsigned long long in,int len);//8 int make_frame_data(my_msg_head *,my_msg_data*,my_msg_tail*,char *in,int in_size); #ifdef __cplusplus } #endif #endif
myprotocol.c
#include <stdio.h> #include <string.h> #include "myprotocol.h" void set_short_value_b(char *out, short in, int len) { if (len != sizeof(short)) return; out[0] = (char)((in >> 8) & 0xff); out[1] = (char)(in & 0xff); } void set_int_value_b(char *out, int in, int len) { if (len != sizeof(int)) return; out[0] = (char)((in >> 24) & 0xff); out[1] = (char)((in >> 16) & 0xff); out[2] = (char)((in >> 8) & 0xff); out[3] = (char)(in & 0xff); } void set_float_value_b(char *out, float in, int len) { if (len != sizeof(float)) return; char *p = (char *)(&in); for (int i = 0; i < 4; i++) { out[i] = p[4 - i - 1]; } } void set_double_value_b(char *out, double in, int len) { if (len != sizeof(double)) return; char *p = (char *)(&in); for (int i = 0; i < 8; i++) { out[i] = p[8 - i - 1]; } } void set_long_long_value_b(char *out, long long in, int len) { if (len != sizeof(long long)) return; char *p = (char *)(&in); for (int i = 0; i < 8; i++) { out[i] = p[8 - i - 1]; } } void set_ushort_value_b(char *out, unsigned short in, int len) { if (len != sizeof(unsigned short)) return; char *p = (char *)(&in); for (int i = 0; i < 2; i++) { out[i] = p[2 - i - 1]; } } void set_uint_value_b(char *out, unsigned int in, int len) { if (len != sizeof(unsigned int)) return; char *p = (char *)(&in); for (int i = 0; i < 4; i++) { out[i] = p[4 - i - 1]; } } void set_ulong_long_value_b(char *out, unsigned long long in, int len) { if (len != sizeof(unsigned long long)) return; char *p = (char *)(&in); for (int i = 0; i < 8; i++) { out[i] = p[8 - i - 1]; } } int make_frame_data(my_msg_head *p_head, my_msg_data *p_data, my_msg_tail *p_tail, char *in, int in_size) { int head_len = sizeof(my_msg_head); int data_len = sizeof(my_msg_data); int tail_len = sizeof(my_msg_tail); int total_len = head_len + data_len + tail_len; if (in_size < total_len) { return -1; } memcpy(in, p_head, head_len); memcpy(in + head_len, p_data, data_len); memcpy(in + head_len + data_len, p_tail, tail_len); return total_len; }
main.c
#include <stdio.h> #include <time.h> #include <unistd.h> #include <string.h> #include "myprotocol.h" void printData(char *data,int len) { printf("data :\n"); for(int i=0;i<len;i++) { printf("%02x ",(unsigned char)data[i]); if(i>0&&((i+1)%10==0)) { printf("\n"); } } printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); } unsigned long long getTime_ms() { struct timespec time1 = {0, 0}; clock_gettime(CLOCK_REALTIME, &time1); unsigned long long ret=((unsigned long long)time1.tv_sec)*1000+((unsigned long long)time1.tv_nsec)/1000/1000+8*60*60*1000; printData((char *)&ret,8); return ret; } int main(int argc, char **argv) { char send_data[512]={0}; my_msg_head m_head; my_msg_data m_data; my_msg_tail m_tail; memset(&m_head,0,sizeof(m_head)); memset(&m_data,0,sizeof(m_data)); memset(&m_tail,0,sizeof(m_tail)); m_head.msg_head[0]=0x05; m_head.msg_head[1]=0x49; m_head.version[1]=0x01; m_head.version[0]=0x00; set_int_value_b(m_head.msg_num,0x1002,sizeof(m_head.msg_num)); set_int_value_b(m_head.reply_num,0x20001,sizeof(m_head.reply_num)); set_ulong_long_value_b(m_head.utc_time,getTime_ms(),sizeof(m_head.utc_time)); set_int_value_b(m_head.data_len,sizeof(my_msg_data),sizeof(m_head.data_len)); set_ulong_long_value_b(m_data.role_id,0x1234,sizeof(m_data.role_id)); set_uint_value_b(m_data.move_type,(unsigned int)0x56789,sizeof(m_data.move_type)); set_uint_value_b(m_data.distance,0x1234,sizeof(m_data.distance)); set_ushort_value_b(m_data.speed,0x5678,sizeof(m_data.speed)); m_tail.msg_tail[0]=0x05; m_tail.msg_tail[1]=0x49; int send_len=make_frame_data(&m_head,&m_data,&m_tail,send_data,sizeof(send_data)); printData(send_data,send_len); /* 小端: 49 05 01 00 02 10 00 00 01 00 02 00 b6 04 9f b0 76 01 00 00 12 00 00 00 34 12 00 00 00 00 00 00 89 67 05 00 34 12 00 00 78 56 49 05 大端: 05 49 00 01 00 00 10 02 00 02 00 01 00 00 01 76 b0 9f 04 b6 00 00 00 12 00 00 00 00 00 00 12 34 00 05 67 89 00 00 12 34 56 78 05 49 */ }