博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网络socket编程——TLV格式及编解码示例
阅读量:3933 次
发布时间:2019-05-23

本文共 8108 字,大约阅读时间需要 27 分钟。

前言:之前做过的网络socket上报温度是基于TCP。和UDP.HTTP一样都是通信协议,也就是通信时所遵守的规则,只有双方按照这个规则“说话”,对方才能理解或为之服务。这里说的协议,都是基于应用层的协议,一切应用层协议说白了,就是数据包的结构定义。至于TLV格式,就是Type-Length-Value ,数据包里放数据,要么用定长,要么用TLV这种可变长度的。同时TLV是一种通用的socket网络协议数据格式。具有扩展兼容性好,解析快,结构性好,数据包小的特点。

一:TCP HTTP UDP三者的关系:

TCP/IP是个协议组,可分为四个层次:网络接口层、网络层、传输层和应用层。
在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。
在传输层中有TCP协议与UDP协议。
在应用层有FTP、HTTP、TELNET、SMTP、DNS等协议。
因此,HTTP本身就是一个协议,是从Web服务器传输超文本到本地浏览器的传送协议。

二:socket:

这是为了实现以上的通信过程而建立成来的通信管道,其真实的代表是客户端和服务器端的一个通信进程,双方进程通过socket进行通信,而通信的规则采用指定的协议。socket只是一种连接模式,不是协议,tcp,udp,简单的说(虽然不准确)是两个最基本的协议,很多其它协议都是基于这两个协议如,http就是基于tcp的,.用socket可以创建tcp连接,也可以创建udp连接,这意味着,用socket可以创建任何协议的连接,因为其它协议都是基于此的。

三:数据包TLV的设计

从应用层HTTP协议,到超文本置标语言HTML(HyperText Mark-up Language),再到可扩展置标语言XML(Extensible Markup Language),它们提供了数据的格式化存储、传输和格式化显示的规范,是网络通信的基石。然而HTTP协议以及HTML/XML置标语言的本质就是定义一堆标签(Tag)对数据进行串行化序列化,然后接收方再根据标签解析、还原数据。

自定义通信协议的关键是对数据包的合理构造(construct)和正确解析(parse),即制定编解码规则。

抽象语法标记 ASN(Abstract Syntax Notation) BER的长度确定的编码方式,由3部分组成Identifier octets、Length octets和Contents octets,实际上这就是一种TLV(Type-Length-Value)模型:类型字段(Type或Tag)是关于标签和编码格式的信息;长度字段(Length)定义数值的长度; 内容字段(Value)表示实际的数值。

因此,一个编码值又称TLV三元组。编码可以是基本型或结构型,如果它表示一个简单类型的、完整的显式值,那么编码就是基本型(primitive);如果它表示的值具有嵌套结构,那么编码就是结构型 (constructed)。

TLV编码就是指对Type(Tag)、Length和Value进行编码,形成比特流;解码是编码的逆过程,是从比特流缓冲区中解析还原出原始数据。

参考博客:

客户端数据装包思路:

在这里插入图片描述
当然中间的T.L.V可以自己随意定义,这个根据自己的实际需求来。
一张图大家应该能看明白:
ID:LSJ 3bytes
时间:原本应该为2019-04-18 21:52:37 2019=119(+1900)
数据包: 119 4 18 21 52 37 6bytes
温度:原本应该为19.56℃
数据包:19 56 2bytes
装包过程明白了原理就很好写
在这里插入图片描述
装包代码:

#define HEAD 0xFD#define ID 0X01#define INT_TIME 0X02#define FLOAT_TEMP 0X03int makepack(char *buf,int size){    int id_len=0;    int data_len=0;    int time_len=0;    int temp_len=0;    int buf_place=0;    int  i;    char *id="lsj";        char datatime[32];        float temp;        unsigned short crc16=0;            if(!buf || size<18)        {            printf("Invalid input arguements\n");            return 0;        }        buf[buf_place]=HEAD;        buf_place+=1;            data_len=11;        buf[buf_place]=data_len;        buf_place+=1;            buf[buf_place]=ID;        buf_place+=1;        id_len=strlen(id);        memcpy(&buf[buf_place],id,id_len);        buf_place+=id_len;                buf[buf_place]=INT_TIME;        buf_place+=1;        memset(datatime,0,sizeof(datatime));        int time=getdatatime(datatime);        time_len=time;        printf("time_len is %d\n",time_len);        for(int i=0;i

CRC校验代码直接网上找的,直接套用。没有深入去了解它。大家有兴趣可以去了解。

四:数据包解包

数据包解包的流程就是装包的逆过程,流程图如下:
在这里插入图片描述
第一次使用yed画流程图,有点糙,哈哈哈
源代码如下:
这里使用了大量的memmove函数,大家可以去了解一下这个函数

#include "tlv.server.h"#include "tlv.crc.h"#define HEAD 0xFD#define ID 0X01#define INT_TIME 0X02#define FLOAT_TEMP 0X03static sqlite3 *db;int dividepack(char *buf,int size){     int     i;     unsigned short crc16=0;     char    user[32];     int     year;     int     month;     int     day;     int     hour;     int     minute;     int     second;     int     temp_1;     int     temp_2;     int     rc;     char    *db_name="TEMP.db";     char    *error=0;     char    *insert=(char*)malloc(256);     char    *select="select * from TEMP;";     char    *sql="CREATE TABLE IF NOT EXISTS TEMP(""ID INT PRIMARY KEY,"                                                    "USER CHAR(10),"                                                    "TIME CHAR(50),"                                                    "TEMP CHAR(10));";     memset(user,0,sizeof(user));     if(!buf||size<=6)     {         printf("Invalid input arguements\n");         return 0;     }flag1:if(size>6)     {    flag2:for(i=0;i
5) { if(buf[i+1]==11) { if(buf[i+2]==ID) { memcpy(user,&buf[i+3],3); printf("user is %s\n",user); if(buf[i+6]==INT_TIME) { year=buf[i+7]; year+=1900; printf("year is %d\n",year); month=buf[i+8]; printf("month is %d\n",month); day=buf[i+9]; printf("day is %d\n",day); hour=buf[i+10]; printf("hour is %d\n",hour); minute=buf[i+11]; printf("minute is %d\n",minute); second=buf[i+12]; printf("second is %d\n",second); if(buf[i+13]==FLOAT_TEMP) { temp_1=buf[i+14]; printf("temp_1 is %d\n",temp_1); temp_2=buf[i+15]; printf("temp_2 is %d\n",temp_2); crc16=crc_itu_t(MAGIC_CRC,buf,18); //ushort_to_bytes(&buf[i+16],crc16); if(crc16==0) { printf("crc true\n"); printf("divide pack finish\n"); memmove(buf,&buf[i],size);size=0; } else { memmove(buf,&buf[i+16],size-i-16);size=size-i-16;goto flag1; } } else { memmove(buf,&buf[i+13],size-i-13);size=size-i-13;goto flag1; } } else { memmove(buf,&buf[i+6],size-i-6);size=size-i-6;goto flag1; } } else { memmove(buf,&buf[i+2],size-i-2);size=size-i-2;goto flag1; } } else { memmove(buf,&buf[i+1],size-i-1);size=size-i-1;goto flag1; } } else { memmove(buf,&buf[i],size-i);return size-i;goto flag1; } } else { goto flag2; } } } else { return size; }

下面部分是数据库的内容

rc=sqlite3_open(db_name,&db);     if(rc!=SQLITE_OK)     {        fprintf(stderr,"sql error:%s\n",sqlite3_errmsg(db));     }     else     {         printf("open sqlite successfully!\n");     }         rc=sqlite3_exec(db,sql,NULL,NULL,&error);     if(rc!=SQLITE_OK)     {         fprintf(stderr,"sql error:%s\n",error);         sqlite3_close(db);         sqlite3_free(error);         exit(1);     }     else     {         printf("create table successfully!\n");     }     snprintf(insert,256,"insert into TEMP(USER,TIME,TEMP)values('%s','%04d-%02d-%02d %02d:%02d:%02d','%d.%d');",user,year,month,day,hour,minute,second,temp_1,temp_2);     rc=sqlite3_exec(db,insert,NULL,NULL,&error);     if(rc!=SQLITE_OK)     {         fprintf(stderr,"sql error:%s\n",error);         sqlite3_close(db);         sqlite3_free(error);         exit(1);     }     else     {         printf("insert successfully!\n");     }          rc=sqlite3_exec(db,select,NULL,NULL,&error);     if(rc!=SQLITE_OK)     {         fprintf(stderr,"sql error:%s\n",error);         sqlite3_close(db);         sqlite3_free(error);         exit(1);     }     else     {         printf("select successfully!\n");     }     sqlite3_close(db);}

后序:这篇博客重点在于理解tlv是干嘛的,有什么作用,以及如何运用它。还有要熟练掌握网络socket编程。

项目源码已上传码云:

转载地址:http://ufhgn.baihongyu.com/

你可能感兴趣的文章
As-Conformal-As-Possible Surface Registration
查看>>
qmake Variable Reference
查看>>
ML 14 part2 principal component analysis
查看>>
Lesson 2 Gradient Desent
查看>>
lesson 5 memory model
查看>>
lesson 6 threads synchronization
查看>>
lesson 7 strategies for efficient CUDA programming
查看>>
using cuda7.0 in matlab2015b with vs2013 compiler
查看>>
convert RGB image with hole into binary image with hole filled
查看>>
rotate object in matlab
查看>>
find border vertex
查看>>
matlab sliced variable
查看>>
create symbolic array
查看>>
TAUCS库的编译(vs2010)
查看>>
color vector using in plotting example points and lines between corresponding vertices
查看>>
laplacian,degree,adjacency and oriented incidence matrix, differential and laplacian coordinates
查看>>
mex 里面调用matlab函数
查看>>
CUDA里面GRID, BLOCK 边界检测
查看>>
matlab中cuda编程中分配grid和block dimension的时候的注意事项
查看>>
GPU CUDA and MEX Programming
查看>>