加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux内核分析 - 网络[十二]:UDP模块 - 收发

发布时间:2016-09-26 03:21:42 所属栏目:Linux 来源:站长网
导读:副标题#e# 内核版本:2.6.34 UDP报文接收 UDP报文的接收可以分为两个部分:协议栈收到udp报文,插入相应队列中;用户 调用recvfrom()或recv()系统调用从队列中取出报文,这里的队列就是sk-sk_receive_queue,它是报文中转的纽带,两部 分的联系如下图所示。

如果没有报文,有两种情况:使用了非阻塞接收,且用户接收时还没有报文到来;使 用阻塞接收,但之前没有报文,且在sk->sk_rcvtimeo时间内都没有报文到来。没有报文,返回错误值。

if (!skb) 

    
 goto out;

len是recvfrom()传入buf的大小,ulen是报文内容的长度,如果ulen > len,那么只需要使用buf的 ulen长度就可以了;如果len < ulen,那么buf不够报文填充,只能对报文截断,取前len个字节。

ulen = skb-

>len - sizeof(struct udphdr);     
if (len > ulen)     
 len = ulen;     
else if (len < ulen)     
 msg->msg_flags |= MSG_TRUNC;

如果报文被截断或使用UDP-Lite,那么需要提前验证校验和, udp_lib_checksum_complete()完成校验和计算,函数在下面具体分析。

if (len < ulen || UDP_SKB_CB(skb)-

>partial_cov) {     
 if (udp_lib_checksum_complete(skb))     
  goto csum_copy_err;     
}

如果报文不用验证校验和,那么执行if部分,调用skb_copy_datagram_iovec()直接拷贝报文到buf中就可以了;如果 报文需要验证校验和,那么执行else部分,调用skb_copy_and_csum_datagram_iovec()拷贝报文到buf,并在拷贝过程中计算校 验和。这也是为什么在内核收到udp报文时为什么先验证校验和再处理的原因,udp报文可能很大,校验和的计算可能很耗时,将 其放在拷贝过程中可以节约开销,当然它的代价是一些校验和错误的报文也会被添加到socket的接收队列上,直到用户真正接收 时它们才会被丢弃。

if (skb_csum_unnecessary(skb))     
 err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, len);     
else {     
 err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);     
 if (err == -EINVAL)     
  goto csum_copy_err;     
}

拷贝地址到msg->msg_name中,在sys_recvfrom()中msg->msg_name=&address,然后address会从内核拷贝 给用户空间的addr。

if (sin) {     
 sin->sin_family = AF_INET;     
 sin->sin_port = udp_hdr(skb)->source;     
 sin->sin_addr.s_addr = ip_hdr(skb)->saddr;     
 memset(sin->sin_zero, 0, sizeof(sin->sin_zero));     
}

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读