加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (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,它是报文中转的纽带,两部 分的联系如下图所示。

下一步是获取路由项rt,如果已连接(调用过connect),则路由信息在connect()时已获取,直接拿就可以了;如果未 连接或拿到的路由项已被删除,则需要重新在路由表中查找,还是使用ip_route_output_flow()来查找,如果是连接状态的 socket,则要用新找到的rt来更新socket,当然,前提条件是之前的rt已过期。

if (rt == NULL) {     
 ……     
 err = ip_route_output_flow(net, &rt, &fl, sk, 1);     
 ……     
 if (connected)     
  sk_dst_set(sk, dst_clone(&rt->u.dst));     
}

存储信息daddr, dport, saddr, sport到cork.fl中,它们会在生成udp报头和计算udp校验和时用到。up- >pending=AF_INET标识了数据添加的开始,下面将开始数据的添加工作。

inet->cork.fl.fl4_dst = daddr;    

 
inet->cork.fl.fl_ip_dport = dport;     
inet->cork.fl.fl4_src = saddr;     
inet->cork.fl.fl_ip_sport = inet->inet_sport;     
up->pending = AF_INET;

如果pending!=0或执行完初始化操作,则直接执行添加数据操作:

up->len表示要发送数据的总长度,包括udp报头,因此每发送一部分数据就要累加它的长度,在发送后up->len被清0。然 后调用ip_append_data()添加数据到sk->sk_write_queue,它会处理数据分片等问题,在 ”ICMP模块” 中有详细分析过。

up->len += ulen;     
getfrag  =  is_udplite ?  udplite_getfrag : ip_generic_getfrag;     
err = ip_append_data(sk, getfrag, msg->msg_iov, ulen,     
  sizeof(struct udphdr), &ipc, &rt,     
  corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);

ip_append_data()添加数据正确会返回0,否则 udp_flush_pending_frames()丢弃将添加的数据;如果添加数据正确,且没有后续的数据到来(由MSG_MORE来标识),则 udp_push_pending_frames()将数据发送给IP层,下面将详细分析这个函数。最后一种情况是当sk_write_queue上为空时,它触 发的条件必须是发送多个报文且sk_write_queue上为空,而实际上在ip_append_data过后sk_write_queue不会为空的,因此正常 情况下并不会发生。哪种情况会发生呢?重置pending值为0就是在这里完成的,三个条件语句都会将pending设置为0。

if (err)     
 udp_flush_pending_frames(sk);     
else if (!corkreq)     
 err = udp_push_pending_frames(sk);     
else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))     
 up->pending = 0;

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

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

热点阅读