Linux内核分析 - 网络[十二]:UDP模块 - 收发
下一步是获取路由项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; (编辑:PHP编程网 - 黄冈站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |