BSD协议栈:UDP输入
- 互联网
- 2025-09-01 05:39:01

UDP输入
输入函数的目标是把UDP数据报放到合适的插口缓存内,然后唤醒该插口上因输入阻塞的所有进程或线程(唤醒需要依靠操作系统的IPC机制)。
分为三个步骤:
1.确认消息并简单处理输入的数据
2.处理目的地址是单播类型的数据报:提交给单个socket即可
3.处理目的地址是广播或多播类型的数据报:需要找到所有需要提交的socket
处理输入的代码如下:
代码主要是验证数据报长度,有两个参数:ip_len 与 uh_ulen,这两个参数都表示数据报长度,正常情况下,它们应该是相等的。
正常情况:
uh_ulen:UDP首部加UDP数据长度
ip_len:数据报内容长度
但我们都知道网络结构是分层的,下一层对上一层来说就是内容,所以有:
#mermaid-svg-sxinoQdOOiTVMcr9 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-sxinoQdOOiTVMcr9 .error-icon{fill:#552222;}#mermaid-svg-sxinoQdOOiTVMcr9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sxinoQdOOiTVMcr9 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-sxinoQdOOiTVMcr9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sxinoQdOOiTVMcr9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sxinoQdOOiTVMcr9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sxinoQdOOiTVMcr9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sxinoQdOOiTVMcr9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sxinoQdOOiTVMcr9 .marker.cross{stroke:#333333;}#mermaid-svg-sxinoQdOOiTVMcr9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sxinoQdOOiTVMcr9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sxinoQdOOiTVMcr9 .cluster-label text{fill:#333;}#mermaid-svg-sxinoQdOOiTVMcr9 .cluster-label span{color:#333;}#mermaid-svg-sxinoQdOOiTVMcr9 .label text,#mermaid-svg-sxinoQdOOiTVMcr9 span{fill:#333;color:#333;}#mermaid-svg-sxinoQdOOiTVMcr9 .node rect,#mermaid-svg-sxinoQdOOiTVMcr9 .node circle,#mermaid-svg-sxinoQdOOiTVMcr9 .node ellipse,#mermaid-svg-sxinoQdOOiTVMcr9 .node polygon,#mermaid-svg-sxinoQdOOiTVMcr9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sxinoQdOOiTVMcr9 .node .label{text-align:center;}#mermaid-svg-sxinoQdOOiTVMcr9 .node.clickable{cursor:pointer;}#mermaid-svg-sxinoQdOOiTVMcr9 .arrowheadPath{fill:#333333;}#mermaid-svg-sxinoQdOOiTVMcr9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sxinoQdOOiTVMcr9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sxinoQdOOiTVMcr9 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-sxinoQdOOiTVMcr9 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-sxinoQdOOiTVMcr9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sxinoQdOOiTVMcr9 .cluster text{fill:#333;}#mermaid-svg-sxinoQdOOiTVMcr9 .cluster span{color:#333;}#mermaid-svg-sxinoQdOOiTVMcr9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sxinoQdOOiTVMcr9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ip_len UDP首部 UDP数据 IP首部 UDP首部 UDP数据ip_len 大于 uh_ulen:代码相信小的那个,也就是uh_ulen,此时调用m_adj丢弃mbuf后面多出来的部分,在校验和检验时会丢弃该数据报。
ip_len 小于 uh_ulen:长度出现严重错误,数据报必须立即被丢弃。
后面就是填写字段并计算校验和,在前文讲过了,就不过多赘述了。
void udp_input(m, iphlen) register struct mbuf *m; int iphlen; { register struct ip *ip; register struct udphdr *uh; register struct inpcb *inp; struct mbuf *opts = 0; int len; struct ip save_ip; udpstat.udps_ipackets++; //此时还没有实现备份IP选项,因此需要丢弃 if (iphlen > sizeof (struct ip)) { ip_stripoptions(m, (struct mbuf *)0); iphlen = sizeof(struct ip); } //如果IP/UDP长度不合理,那么重新安排mbuf链,使第一个mbuf至少有28个字节 ip = mtod(m, struct ip *); if (m->m_len < iphlen + sizeof(struct udphdr)) { if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { udpstat.udps_hdrops++;//状态标志位,这些代码不影响理解 return; } ip = mtod(m, struct ip *); } uh = (struct udphdr *)((caddr_t)ip + iphlen); /* * Make mbuf data length reflect UDP length. * If not enough data to reflect UDP length, drop. */ len = ntohs((u_short)uh->uh_ulen); if (ip->ip_len != len) { if (len > ip->ip_len) { udpstat.udps_badlen++; goto bad; } m_adj(m, len - ip->ip_len); /* ip->ip_len = len; */ } /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. */ save_ip = *ip; /* * Checksum extended UDP header and data. */ if (udpcksum && uh->uh_sum) { ((struct ipovly *)ip)->ih_next = 0; ((struct ipovly *)ip)->ih_prev = 0; ((struct ipovly *)ip)->ih_x1 = 0; ((struct ipovly *)ip)->ih_len = uh->uh_ulen; if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) { udpstat.udps_badsum++; m_freem(m); return; } } 后面的程序依次是: 分用多播和广播数据报 分用单播数据报 生成ICMP端口不可达差错BSD协议栈:UDP输入由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“BSD协议栈:UDP输入”