我有一个小函数,试图打印IP头的片段偏移量。
ParseIpHeader(unsigned char *packet, int len)
{
struct ethhdr *ethernet_header;
struct iphdr *ip_header;
/* First Check if the packet contains an IP header using
the Ethernet header */
ethernet_header = (struct ethhdr *)packet;
if(ntohs(ethernet_header->h_proto) == ETH_P_IP)
{
/* The IP header is after the Ethernet header */
if(len >= (sizeof(struct ethhdr) + sizeof(struct iphdr)))
{
ip_header = (struct iphdr*)(packet + sizeof(struct ethhdr));
/* print the Source and Destination IP address */
//printf("Dest IP address: %s\n", inet_ntoa(ip_header->daddr));
//printf("Source IP address: %s\n", inet_ntoa(ip_header->saddr));
printf("protocol %d\n", ip_header->protocol);
printf("Fragment off is %d\n", ntohs(ip_header->frag_off));
}
}
我的数据包是TCP(ip_header->协议始终是6.问题是frag_off 总是16384.我发送了大量数据,为什么frag_off总是不变?
感谢。
答案 0 :(得分:3)
片段偏移与标志共享。你有“DF”(不要分段)位集。
如果片段偏移为0,则为整个16位字段提供16384。
从第10页开始,查看http://www.ietf.org/rfc/rfc791.txt。
修改强>:
您正在接收的TCP段中的DF位由远程端设置,以执行Path MTU discovery - 简而言之,尝试避免碎片。 在这种情况下,发送方学习整个路径可以处理的最大MTU,并切断TCP段,使得它们在封装到IP之后不超过它。
<强> EDIT2 强>:
关于recvfrom()和TCP的使用:TCP是面向连接的协议,并且所有分段/碎片细节都已经由它处理(碎片明显由下层IP处理) - 所以你做不需要处理它。你在发送方写的任何东西()最终都会在另一方面读取() - 可能不在同一块中 - 即两次4K写入有时会导致单个8K读取,有时候两次4K读取 - 取决于媒体之间关于重新排序/丢失的行为。
IP碎片和重组由操作系统透明地处理,因此您不必担心它,与无序数据包相同等等(您将看到性能下降对应用程序的影响)
我可以推荐一个很好的读物:UNIX network programming。鉴于史蒂文参与TCP,无论您使用哪种操作系统,它都是一本好书。
<强> EDIT3:强>
如果你做的事情是“中间人”(假设你有合理的理由:-) - 那么你可以通过查看现有技术评估即将开展的工作:{{3 (一个脚本方法,适用于pcap文件,但适用于其他东西),或chaosreader - 它模拟IP碎片整理和TCP流重组;也许只是为了你的目的重复使用它们。