linux内核代码-注释详解:tcp_recvmsg

tcp_recvmsg函数处理从接收缓冲区读取数据到用户缓冲区的过程,涉及TCP连接状态检查、错误队列处理、接收紧急数据、MSG_PEEK标志处理以及接收时间戳等。在遍历接收队列并拷贝数据的同时,还会处理FIN标志、接收超时和信号中断等情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/* linux-5.10.x\net\ipv4\tcp.c
* 从接收缓冲区中读取数据,并将其拷贝到用户提供的缓冲区中。该函数还负责处理一些特殊情况,如接收紧急数据和查看发送队列中的数据
	1、从接收缓冲区中读取数据,并将其拷贝到用户提供的缓冲区中
	2、处理接收到的FIN标志,表示连接的一端已关闭
	3、处理MSG_PEEK标志,如果设置了该标志,则不会从接收缓冲区中删除数据
	4、处理接收时间戳,如果设置了相应的控制消息标志,则会设置接收时间戳
	5、处理接收队列长度控制消息,如果设置了相应的控制消息标志,则会获取接收队列长度的提示,并设置控制消息
*/
int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
		int flags, int *addr_len)
{
   
	struct tcp_sock *tp = tcp_sk(sk);		//将TCP套接字的指针转为tcp_sock类型的指针,以便访问TCP套接字特定的成员变量
	int copied = 0;							//用于记录拷贝的字节数
	u32 peek_seq;							//用于记录MSG_PEEK的序列号
	u32 *seq;								//用于指向数据包的序列号
	unsigned long used;						//用于记录已使用的缓冲区大小
	int err, inq;							//用于记录错误码和入队标志
	int target;								/* Read at least this many bytes 表示至少需要读取的字节数*/
	long timeo;								//表示接收超时时间
	struct sk_buff *skb, *last;				//用于在数据包链表中遍历
	u32 urg_hole = 0;						//表示紧急数据的空隙
	struct scm_timestamping_internal tss;	//用于存储时间戳信息
	int cmsg_flags;							//表示控制消息的标志位

	/* unlikely()宏不会改变程序逻辑,只用于提示编译器某个条件的发生概率较低,让编译器更加关注对其他分支的优化,从而提高代码执行的效率 */
	if (unlikely(flags & MSG_ERRQUEUE))					//有错误队列消息
		return inet_recv_error(sk, msg, len, addr_len);	//处理接收错误队列,并返回结果

	if (sk_can_busy_loop(sk) && skb_queue_empty_lockless(&sk->sk_receive_queue) &&
	    (sk->sk_state == TCP_ESTABLISHED))				//套接字类型支持忙等待、接收队列为空、TCP套接字处于已建立状态
		sk_busy_loop(sk, nonblock);						//在非阻塞模式下进行忙等待

	lock_sock(sk);										//锁定套接字,以保证在执行后续操作时的线程安全

	err = -ENOTCONN;									//将错误码设置为未连接
	if (sk->sk_state == TCP_LISTEN)						//如果套接字状态为监听状态
		goto out;										//则跳转到out标签,表示连接未建立

	cmsg_flags = tp->recvmsg_inq ? 1 : 0;				//根据TCP套接字接收消息入队标志,设置控制消息的标志位
	timeo = sock_rcvtimeo(sk, nonblock);				//获取接收超时时间

	/* Urgent data needs to be handled specially. */
	if (flags & MSG_OOB)								//如果有应急数据
		goto recv_urg;									//则跳转到recv_urg标签,表示接收紧急数据

	if (unlikely(tp->repair)) {
   							//如果TCP套接字处于损坏修复状态
		err = -EPERM;									//将错误码设置为权限不足
		if (!(flags & MSG_PEEK))						//如果flags参数中不包含MSG_PEEK标志位
			goto out;									//则跳转到out标签,表示权限错误

		if (tp->repair_queue == TCP_SEND_QUEUE)			//如果修复队列为发送队列
			goto recv_sndq;							//则跳转到处理发送队列

		err = -EINVAL;									//将错误码设置为无效参数
		
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值