//linux-5.10.x\net\socket.c
SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
unsigned int, flags, struct sockaddr __user *, addr,
int __user *, addr_len)
{
return __sys_recvfrom(fd, ubuf, size, flags, addr, addr_len);
/*参数
int, fd:表示文件描述符。
void __user *, ubuf:表示接收数据的缓冲区
size_t, size:表示接收数据的最大长度
unsigned int, flags:表示标志参数
struct sockaddr __user *, addr:表示指向存储发送方地址信息的结构体的指针
int __user *, addr_len:表示发送方地址信息的长度
*/
}
int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags,
struct sockaddr __user *addr, int __user *addr_len)
{
struct socket *sock; // 套接字指针
struct iovec iov; // 消息数据缓冲区描述符
struct msghdr msg; // 消息头描述符
struct sockaddr_storage address; // 存储目标地址信息的结构体
int err, err2; // 错误码
int fput_needed; // 是否需要减少引用计数
err = import_single_range(READ, ubuf, size, &iov, &msg.msg_iter); // 将用户空间缓冲区(ubuf)导入为内核空间的数据,以便进行读取或操作
/*参数:
READ:表示要从用户空间读取数据到内核空间
ubuf:指向用户空间缓冲区的指针
size:用户空间缓冲区的大小
&iov:保存导入过程中的权限和偏移信息
&msg.msg_iter:保存导入过程中的迭代状态信息*/
if (unlikely(err))
return err;
sock = sockfd_lookup_light(fd, &err, &fput_needed); // 根据给定的文件描述符fd在内核中查找对应的套接字(socket)
if (!sock)
goto out;
/* 以下字段用于在进行套接字传输时指定相关的参数和选项 */
msg.msg_control = NULL; // 不使用辅助数据(ancillary data),将消息控制信息置为 NULL
msg.msg_controllen = 0; // 辅助数据长度为 0,即没有辅助数据
msg.msg_name = addr ? (struct sockaddr *)&address : NULL; // 根据条件判断是否需要设置目的地址。如果需要,将地址复制到用户空间
msg.msg_namelen = 0; // 目的地址长度为 0,即不使用目的地址
msg.msg_iocb = NULL; // 不使用 I/O 控制块,将其置为 NULL
msg.msg_flags = 0; // 不设置任何标志
if (sock->file->f_flags & O_NONBLOCK) // 检查套接字文件描述符的状态是否为非阻塞模式O_NONBLOCK
flags |= MSG_DONTWAIT; // 如为非阻塞模式,则设置MSG_DONTWAIT标志,表示设置消息传输为非阻塞模式
err = sock_recvmsg(sock, &msg, flags); // 通过给定的套接字 sock接收数据和消息信息,并存到msg,返回接收到的字节数
if (err >= 0 && addr != NULL) { // 如果接收成功且需要返回地址信息,
err2 = move_addr_to_user(&address,
msg.msg_namelen, addr, addr_len); // 则将地址信息复制到用户空间
if (err2 < 0)
err = err2;
}
fput_light(sock->file, fput_needed); // 释放套接字引用计数
out:
return err;
}
linux内核代码-注释详解:recvfrom & __sys_recvfrom
最新推荐文章于 2023-07-06 19:36:52 发布