linux网络协议栈(六)传输层 (3)UDP协议 4)报文接收 recv/recvfrom/recvmsg

6.2.2.2.5、报文接收:

recv/recvfrom/recvmsg和send族系统调用的道理是一样的,如下图:


sock_recvmsg函数最终调用套接字类型ops的recvmsg方法,对于数据报套接字为函数sock_common_recvmsg,它实际调用传输层协议ops的recvmsg方法,对于UDP协议为函数udp_recvmsg,注意传输层协议ops的三类recvmsg也是各异的;

注意,实际报文的接收参见4.2.2.2.2一节末尾的udp_rcv函数处理流程,它将传输层收到的报文,根据bind中绑定的接收地址在UDP协议绑定表中找到应该转送的传输通道sock的接收队列(sock->sk_receive_queue),所以这里recv族实际只是从传输通道sock的接收队列中获取报文;

另外,当传输通道sock的接收队列中暂时没有报文时,如果该socket文件读属性为阻塞,那么应用程序将被睡眠,直到超时或者有报文进入传输通道sock的接收队列,非阻塞的情况下将直接返回;

udp_recvmsg函数的主要流程如下:


1、调用函数__skb_recv_datagram获取报文,在获取到报文后根据获取长度和预先希望获取的长度调整返回长度,原则是“用户进程希望获取的长度如果大于实际长度则应置copied为实际长度,否则要加标志位MSG_TRUNC还要检查校验和”,然后把报文内容复制到msghdr描述符的数据内容字段中(msg_iov);

报文的实际接收函数方式,就是在传输通道sock的接收队列(sk->sk_receive_queue)不为空时,从中摘除最旧的一个报文并返回(skb_peek),若为空,则陷入睡眠直到有报文被接收或超时(见函数wait_for_packet,定时阻塞,超时或被信号触发均被唤醒),超时时间在初始化时指定为无限长,可由setsockopt系统调用修改;如下图:


2、服务器是如何获知客户端的地址的?正是在这里!在报文接收中,接收方不仅接收报文数据,同样记录了报文发送者的地址,如下图:


上图中sin是recvfrom系统调用的第五个参数,它用于应用程序记录发送给它报文的发送者地址,它的被赋值就是在这里,根据收到的报文的IP协议头的源IP、UDP协议头的源端口,获知了对端地址;

3、到这里,这个报文的使命也就正式结束了,该skb将被释放:


至此,报文接收流程结束,要明确:

1、传输通道sock的接收队列存在报文时,应用程序摘除一个最旧的报文,否则应用程序阻塞直至超时或者有报文可接收;超时时间可由setsockopt设置;

2、除接收数据外,还会记录发送者的地址到应用程序(由recvfrom系统调用的第五参数),这样应用程序即可尝试回复报文给该发送者


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值