博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
TCP/IP协议栈 --- 网络层(IP 首部 和分片)
阅读量:6368 次
发布时间:2019-06-23

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

IP 是TCP/IP协议栈中重要的层次, TCP UDP ICMP IGMP都是依赖IP层进行传输的。首先它是一种不可靠,无连接的协议。不可靠:它不保证IP包能正确到达目的地,无连接:表示IP并不会维护后续数据包的信息,每个数据包的传输都是独立的。数据包的可靠性需要依赖传输层协议来保证如TCP协议,也就是说当一个比特流从网络接口发送向网络之后,所经过的每个路由器会解析数据包的网络层的信息,再通过路由算法选一条路发送出去,所有包不一定会选择同一条道路。网络层负责点到点的通信,尽量将数据包发送到目的主机,若不能到达目的主机IP有一个简单的错误处理算法:丢弃该数据报,然后发送 ICMP消息报给信源端。

IP首部信息:

这里写图片描述

如果没有IP选项的话IP首部应该是20字节。用wireshark抓包分析一下

这里写图片描述

4位版本号: 0100 表示IPv4 若是IPv6的话应该是0110

4位首部长度:0101 表示20个字节,这是因为首部长度指的是首部占 32 bit字的数目,包括任何选项。由于它是一个 4比特字段,因此首部最长为6 0个字节。也就是说这四个比特一个比特表示4个字节。
8位服务类型:服务类型(TO S)字段包括一个3 bit的优先权子字段(现在已被忽略) ,4 bit的TOS子字段和1 bit未用位但必须置0。4 bit的TOS分别代表:最小时延、最大吞吐量、最高可靠性和最小费用。普通数据包里一般都为0x00. 对于不同应用可能会选择不同的TOS。如TFTP telnet等。
16位总长度:表明IP数据包的总长度 最大65535个字节, 但考虑到链路层的MTU 一般这个值要小于1500。拿这个总长度减去IP首部长度就是TCP UDP 等数据包长度。
接下来的4个字节就是表示IP分片的记录信息:
这里写图片描述
前两个字节表示:那个数据包的分片,标识同一个数据报分片
3位标志表示:是否有更多分片,最后一个IP分片里都为0表示没有分片了
13位片偏移:分片在原始数据的偏移量。
另外在分片过程中传输层信息只会出现在第一个分片中。IP层不知道也不需要保证在每个分片中都有传输层首部。到达目的主机时IP层会把这些IP片组合起来。若有片丢失的话,就会重传整个数据报。组合起来的数据报再交给传输层解析。
这里写图片描述

最后的几个字节包含目的IP源IP和IP选项(若有)。

下面做一个UDP传输实例看一下IP层分片。

#include 
#include
#include
#include
#include
#include
#define PORT 4444int main(int argc, char *argv[]){ if(argc != 2) { printf("./udpclient IP\n"); return 1; } int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return 1; struct sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons(PORT); if (!inet_pton(AF_INET, argv[1], (void *)&server.sin_addr)) { printf("IP error\n"); return -1; } char buff1[65535] = "sdfsdfsdf"; char buff2[2048] = { 0}; socklen_t size = sizeof(struct sockaddr); while(1) { sendto(fd, buff1, 65535, 0, (const struct sockaddr *)&server, size); sleep(5); recvfrom(fd, buff2, 2048, 0, NULL, NULL); printf("recv : %s\n", buff2); }}

服务器端

#include 
#include
#include
#include
#include
#include
#define PORT 4444int main(){ int fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd < 0) return -1; struct sockaddr_in server, client; server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr.s_addr = htonl(INADDR_ANY); bind(fd, (const struct sockaddr *)&server, sizeof(struct sockaddr)); socklen_t len = sizeof(struct sockaddr); char buff[2048] = { 0}; while(1) { recvfrom(fd, buff, 2048, 0,(struct sockaddr *)&client, &len); printf("%s send msg: %s \n", inet_ntoa(client.sin_addr), buff); sendto(fd, "OK", 2, 0, (const struct sockaddr *)&client, len); }}

抓包结果可以看到:

~# tcpdump -i eth0 -v udp and host 192.168.1.3tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes18:21:40.171370 IP (tos 0x0, ttl 64, id 39920, offset 0, flags [+], proto UDP (17), length 1500)    192.168.1.3.39170 > 192.168.1.4.4444: UDP, length 204818:21:40.171385 IP (tos 0x0, ttl 64, id 39920, offset 1480, flags [none], proto UDP (17), length 596)

这里可以看到被分成的两个组,2096 - 2048 = 48字节: 多出的48个字节包含俩个IP头40 + 一个UDP头8 字节??

转载于:https://www.cnblogs.com/MaAce/p/7755702.html

你可能感兴趣的文章
app store 增量更新
查看>>
词霸英语积累
查看>>
位运算符——管理事务的开关状态
查看>>
Java日志组件1---Jdk自带Logger(java.util.logging.Logger)
查看>>
php 与 ajax 获取123的案例
查看>>
PHP2014.5.14的总结:
查看>>
如何成为Python高手[转]
查看>>
读《人月神话》有感2
查看>>
安装并解决purcell/emacs.d网络问题
查看>>
趋势科技:微软已修复IE7的最新安全漏洞
查看>>
微软发布1月安全补丁 09年第一安全公告
查看>>
开发者最希望看到的C# 4.0新特性,徐汇区网站设计
查看>>
ISO C++委员会批准C++0x最终草案
查看>>
用好IE9浏览器必须要知道的九件事
查看>>
一起谈.NET技术,从原理来看Silverlight 4的架构
查看>>
艾伟:让.NET程序脱离.NET Framework框架运行
查看>>
艾伟_转载:Lucene.net多字段多索引目录搜索
查看>>
【机器学习】一般线性回归
查看>>
[FFT]luogu P1919 A*B Problem升级版
查看>>
linux -- 进程的查看、进程id的获取、进程的杀死
查看>>