UDP之数据报接收过程(二)


UDP数据报的接收过程要分两部分来看:

  1. 网络层将数据报递交给UDP后,UDP的处理过程。该过程中,UDP需要接收数据包并对其进行校验,校验成功后将其放入接收队列中等待用户空间程序来读取;
  2. 用户空间程序调用read()等系统调用读取已经放入接收队列中的数据。

这篇笔记记录了第二步。

系统调用: udp_recvmsg()

对于应用程序而言,读操作可以通过多个系统调用实现,如read()、recv()、recvfrom()等等,但是这些系统调用到了传输层协议,都调用到了同一接口,对于UDP就是udp_recvmsg()。

int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
		size_t len, int noblock, int flags, int *addr_len)
{
   
	struct inet_sock *inet = inet_sk(sk);
	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
	struct sk_buff *skb;
	unsigned int ulen, copied;
	int peeked;
	int err;
	int is_udplite = IS_UDPLITE(sk);

	// 需要返回源地址信息,设置源地址长度
	if (addr_len)
		*addr_len = sizeof(*sin);

	// 如果设置了MSG_ERRQUEUE标记,那么只读取错误信息
	if (flags & MSG_ERRQUEUE)
		return ip_recv_error(sk, msg, len);

try_again:
	// 根据是否需要阻塞,从接收队列中取出一个skb
	skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), &peeked, &err);
	if (!skb)
		goto out;

	// ulen为该skb中包含的数据载荷长度
	ulen = skb->len - sizeof(struct udphdr);
	// len为应用程序指定的buffer大小,所以下面的逻辑含义为:
	// 1. 如果应用提供的buffer超过了该数据包的数据长度,那么调整要拷贝的数据量为该skb的实际数据量
	// 2. 如果应用提供的buffer不够大,那么需要截断数据包,并设置截断标记
	copied = len;
	if (copied > ulen)
		copied = ulen;
	else if (copied < ulen)
		msg->msg_flags |= MSG_TRUNC;

	/*
	 * If checksum is needed at all, try to do it while copying the
	 * data.  If the data is truncated, or if we only want a partial
	 * coverage checksum (UDP-Lite), do it before the copy.
	 */
	// 对于截断的数据包和尚未完成校验的数据包,先进行校验,校验出错则尝试读取下一个数据包
	// 条件二实际上只用于UDPLite,因为UDP协议的校验在接收过程的第一步就完成了
	if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
   
		if (udp_lib_checksum_complete(skb))
			goto csum_copy_err;
	}
	// 根据是否需要校验,调用不同的数据拷贝函数
	if (skb_csum_unnecessary(skb))
		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied);</
  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值