协议传输机制
WEB服务器和客户计算机得交互过程简述如下:
1、应用层协议栈软件将文件数据进行提取封装,并添加HTTP协议报头向传输层进行传输
2、传输层协议栈软件在上层传递下来得数据包基础上继续添加TCP报头向链路层进行传输
3、链路层协议栈软件在上层传递下来得数据包基础上继续添加IP头/IP地址然后通过以太网接口将逻辑信号转为物理链路得物理信号
4、客户计算机提取物理链路上得物理型号并进行逻辑信号转换,然后依次剔除各层报头,一直往客户计算机应用层传递
包的结构
从上面的交互流程来看,主机和服务器交互时最重要的不是文件文本的数据,而是各层协议的包头,那定义包头需要考虑的核心问题就是:需要各层协议栈软件支持对应包头和不通数据长度包处理。
那可以简单定义为下面的数据包结构:包的有效长度+指向添加包头的指针+文件数据,那可以定义为一个结构体:
/*定义以太网包的成员及相关参数*/
#define PACKET_SIZE 1516 //以太网链路的最大就是1514,考虑CRC则是1516
typedef struct _eth_packet
{
uint16_t size;//包大小
uint8_t* dataptr;//指向包头的指针
uint8_t payload[PACKET_SIZE];//存放文本数据和各协议栈包头
}_eth_packet;
_eth_packet tx_packet;
_eth_packet rx_packet;
操作包
在定义好基本的数据包格式后,我们需要定义数据包的发送、接收、包头增加、包头移除四个最基本的函数,至于包中实际数据的操作,我们在说到各协议时再提:
数据包发送与接收
/*
brief:处理tx的数据
return:返回处理好的数据地址指针
*/
_eth_packet* tx_xnet_packet(_eth_packet* eth_packet, uint16_t rsize)
{
eth_packet->dataptr = tx_packet.payload + PACKET_SIZE;
eth_packet->size = rsize;
return eth_packet;
}
/*
brief:处理rx的数据
return:返回处理好的数据地址指针
*/
_eth_packet* rx_xnet_packet(_eth_packet* eth_packet, uint16_t rsize)
{
//分配文件的缓冲空间
eth_packet->dataptr = eth_packet->payload;//直接指向数据包的地址
eth_packet->size = rsize;
return eth_packet;
}
需要注意几个点,首先我们不可以将struct eth_packet
按值传递,如果想要按值传递,请将你得数据包声明为static
,例如:
static _eth_packet tx_packet;
static _eth_packet rx_packet;
其次就是指针的移动方向需要设置为<<
,这是因为以太网的数据包总是增删包头,因此将包尾视为指针基地址比较合理,此操作在包头的增删函数中会有体现。
包头的增删
/*
brief:添加包头
return:返回处理好的数据地址指针
*/
_eth_packet* add_header(_eth_packet* eth_packet, uint16_t rsize/*包头大小*/)
{
eth_packet->dataptr -= rsize;//包中首个数据的地址
eth_packet->size += rsize;//数据长度=原本数据长度+包头大小
return eth_packet;
}
/*
brief:去除包头
return:返回处理好的数据地址指针
*/
_eth_packet* del_header(_eth_packet* eth_packet, uint16_t rsize)
{
eth_packet->dataptr += rsize;
eth_packet->size -= rsize;
return eth_packet;
}
可以看出在add_header()
中的eth_packet->dataptr -= rsize;
正是基于包指针地址为结尾的思想去实现的。
包的截取
在操作eth_packet.payload[]
数据前我们首先需要检查包的数据长度是否合理,过长则需要截取然后立即转发,这一思想和Autosar-PDUR中的gatingway-on-fly类似,本次练习我们只截取,不做分批发送:
_eth_packet* truncate_header(_eth_packet* eth_packet, uint16_t rsize)
{
eth_packet->size = ((eth_packet->size)>(rsize)) ? rsize : eth_packet->size;//取最小值
return eth_packet;
}