计算机网络-数据帧结构

计算机网络-数据结构-MAC帧头-IP头-TCP头-UDP头
第0章 数据是如何进行一步步的封装的
在这里插入图片描述

第一章:mac帧头定义

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

帧头数据结构的定义:

一、MAC帧头定义

/数据帧定义,头14个字节,尾4个字节/
typedef struct _MAC_FRAME_HEADER
{
char m_cDstMacAddress[6]; //目的mac地址 6字节
char m_cSrcMacAddress[6]; //源mac地址 6字节
short m_cType;      //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp 占用2字节
}attribute((packed))MAC_FRAME_HEADER,*PMAC_FRAME_HEADER;

typedef struct _MAC_FRAME_TAIL
{//占用4字节
unsigned int m_sCheckSum; //数据帧尾校验和,侦校验:FrameCheckSequence:这个字段包括4字节循环冗余校检码(CRC)用于检查错误
}attribute((packed))MAC_FRAME_TAIL, *PMAC_FRAME_TAIL;
  
在这里插入图片描述

ip头部定义

车过来看

在这里插入图片描述

1.源端口和目的端口字段——各占 2 字节。各包含一个TCP端口编号,分别标识连接两端的两个应用程序。本地的端口编号与IP主机的IP地址(32位)形成一个惟一的套接字。双方的套接字惟一定义了一次连接。

2.序号字段——占 4 字节。TCP 连接中传送的数据流中的每一个字节都编上一个序号。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。

3.确认号字段——占 4 字节,是期望收到对方的下一个报文段的数据的第一个字节的序号。

  1. 数据偏移——(占有一个字节)占 4 bit,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。“数据偏移”的单位不是字节而是 32 bit 字 (4 字节为计算单位)。

    保留字段——(占有1.5个字节)占 6 bit,保留为今后使用,但目前应置为 0。

    紧急比特 URG —— 当 URG = 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。

    确认比特 ACK —— 只有当 ACK =1 时确认号字段才有效。当 ACK = 0 时,确认号无效。

    推送比特 PSH (PuSH) —— 接收 TCP 收到推送比特置 1 的报文段,就尽快地交付给接收应用进程,而不再等到整个缓存都填满了后再向上交付。

    复位比特 RST (ReSeT) —— 当 RST  1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。

同步比特 SYN —— 同步比特 SYN 置为 1,就表示这是一个连接请求或连接接受报文。

终止比特 FIN (FINal) —— 用来释放一个连接。当FIN  1 时,表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。

窗口字段 —— 占 2 字节。窗口字段用来控制对方发送的数据量,单位为字节。TCP 连接的一端根据设置的缓存空间大小确定自己的接收窗口大小,然后通知对方以确定对方的发送窗口的上限。

检验和 —— 占 2 字节。检验和字段检验的范围包括首部和数据这两部分。在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。

紧急指针字段 —— ( 占 2 字节)占 16 bit。紧急指针指出在本报文段中的紧急数据的最后一个字节的序号。

/TCP头定义,共20个字节/
typedef struct _TCP_HEADER
{
//第一行
short m_sSourPort;       // 源端口号16bit
short m_sDestPort;        // 目的端口号16bit
//第二行
unsigned int m_uiSequNum;   // 序列号32bit
//第三行
unsigned int m_uiAcknowledgeNum; // 确认号32bit
//第四行
short m_sHeaderLenAndFlag;   // 前4位:TCP头长度;中6位:保留;后6位:标志位
short m_sWindowSize;      // 窗口大小16bit
//第五行
short m_sCheckSum;       // 检验和16bit
short m_surgentPointer;      // 紧急数据偏移量16bit
}attribute((packed))TCP_HEADER, *PTCP_HEADER;

在这里插入图片描述
在这里插入图片描述

数据结构的定义
/UDP头定义,共8个字节/

typedef struct _UDP_HEADER
{
unsigned short m_usSourPort;    // 源端口号16bit
unsigned short m_usDestPort;    // 目的端口号16bit
unsigned short m_usLength;     // 数据包长度16bit
unsigned short m_usCheckSum;   // 校验和16bit
}attribute((packed))UDP_HEADER, *PUDP_HEADER;

在这里插入图片描述

版本(Version)字段:占4比特。用来表明IP协议实现的版本号,当前一般为IPv4,即0100。

报头长度(Internet Header Length,IHL)字段:占4比特。是头部占32比特的数字,包括可选项。普通IP数据报(没有任何选项),该字段的值是5,即160比特=20字节。此字段最大值为60字节。

服务类型(Type of Service ,TOS)字段:占8比特。其中前3比特为优先权子字段(Precedence,现已被忽略)。第8比特保留未用。第4至第7比特分别代表延迟、吞吐量、可靠性和花费。当它们取值为1时分别代表要求最小时延、最大吞吐量、最高可靠性和最小费用。这4比特的服务类型中只能置其中1比特为1。可以全为0,若全为0则表示一般服务。服务类型字段声明了数据报被网络系统传输时可以被怎样处理。例如:TELNET协议可能要求有最小的延迟,FTP协议(数据)可能要求有最大吞吐量,SNMP协议可能要求有最高可靠性,NNTP(Network News Transfer Protocol,网络新闻传输协议)可能要求最小费用,而ICMP协议可能无特殊要求(4比特全为0)。实际上,大部分主机会忽略这个字段,但一些动态路由协议如OSPF(Open Shortest Path First Protocol)、IS-IS(Intermediate System to Intermediate System Protocol)可以根据这些字段的值进行路由决策。

总长度字段:占16比特。指明整个数据报的长度(以字节为单位)。最大长度为65535字节。

标志字段:占16比特。用来唯一地标识主机发送的每一份数据报。通常每发一份报文,它的值会加1。

标志位字段:占3比特。标志一份数据报是否要求分段。

段偏移字段:占13比特。如果一份数据报要求分段的话,此字段指明该段偏移距原始数据报开始的位置。

生存期(TTL:Time to Live)字段:占8比特。用来设置数据报最多可以经过的路由器数。由发送数据的源主机设置,通常为32、64、128等。每经过一个路由器,其值减1,直到0时该数据报被丢弃。

协议字段:占8比特。指明IP层所封装的上层协议类型,如ICMP(1)、IGMP(2) 、TCP(6)、UDP(17)等。

头部校验和字段:占16比特。内容是根据IP头部计算得到的校验和码。计算方法是:对头部中每个16比特进行二进制反码求和。(和ICMP、IGMP、TCP、UDP不同,IP不对头部后的数据进行校验)。

源IP地址、目标IP地址字段:各占32比特。用来标明发送IP数据报文的源主机地址和接收IP报文的目标主机地址。

可选项字段:占32比特。用来定义一些任选项:如记录路径、时间戳等。这些选项很少被使用,同时并不是所有主机和路由器都支持这些选项。可选项字段的长度必须是32比特的整数倍,如果不足,必须填充0以达到此长度要求。

在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的C++函数,能够实现帧头帧尾校验,读取带有帧头帧尾的数据帧,并储存到一个数组中: ```c++ #include <iostream> #include <vector> using namespace std; const int FRAME_SIZE = 10; // 帧的大小 const char FRAME_HEAD = '#'; // 帧头 const char FRAME_TAIL = '$'; // 帧尾 vector<char> readDataWithFrame() { vector<char> frame; // 存储数据帧的数组 char c; bool readFrame = false; // 是否正在读取数据帧 while (cin.get(c)) { if (c == FRAME_HEAD) { // 如果读到帧头 if (readFrame) { // 如果正在读取数据帧,则说明上一帧没有正常结束 cerr << "Error: Frame not end" << endl; frame.clear(); // 清空数据帧 } readFrame = true; frame.clear(); // 清空之前的数据帧 } else if (c == FRAME_TAIL) { // 如果读到帧尾 readFrame = false; if (frame.size() != FRAME_SIZE) { // 如果数据帧长度不正确 cerr << "Error: Frame size not correct" << endl; frame.clear(); // 清空数据帧 } else { // 数据帧长度正确 // 校验帧头帧尾 if (frame[0] != FRAME_HEAD || frame[FRAME_SIZE - 1] != FRAME_TAIL) { cerr << "Error: Frame head or tail not correct" << endl; frame.clear(); // 清空数据帧 } else { return frame; // 返回正确的数据帧 } } } else if (readFrame) { // 如果正在读取数据帧 frame.push_back(c); // 将字符加入数据帧数组 } } cerr << "Error: No frame found" << endl; frame.clear(); // 清空数据帧 return frame; // 返回空的数据帧 } int main() { vector<char> frame = readDataWithFrame(); for (char c : frame) { cout << c; } cout << endl; return 0; } ``` 该函数会从标准输入中读取字符,每当读到帧头时,就开始读取数据帧;当读到帧尾时,就校验帧头帧尾并返回正确的数据帧;如果在读取数据帧过程中发现数据帧长度不正确或帧头帧尾不正确,则清空数据帧并继续寻找下一个帧头。如果一直没有找到帧头,则返回空的数据帧

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值