套接字之recvfrom系统调用

recvfrom系统调用通过用户传入的接收空间构造msghdr,并且调用sock_recvmsg,该函数调用socket操作的recvmsg函数sock->ops->recvmsg,ipv4对应的是inet_recvmsg,该函数调用传输层的sk->sk_prot->recvmsg来接收数据,如tcp则调用tcp_recvmsg,接收完成之后记录地址结构长度信息;

 1 /*
 2  *    Receive a frame from the socket and optionally record the address of the
 3  *    sender. We verify the buffers are writable and if needed move the
 4  *    sender address from kernel to user space.
 5  */
 6
 7 SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
 8         unsigned int, flags, struct sockaddr __user *, addr,
 9         int __user *, addr_len)
10 {
11     struct socket *sock;
12     struct iovec iov;
13     struct msghdr msg;
14     struct sockaddr_storage address;
15     int err, err2;
16     int fput_needed;
17
18     /* 构造msghdr */
19     err = import_single_range(READ, ubuf, size, &iov, &msg.msg_iter);
20     if (unlikely(err))
21         return err;
22
23     /* 查找消息控制块 */
24     sock = sockfd_lookup_light(fd, &err, &fput_needed);
25     if (!sock)
26         goto out;
27
28     msg.msg_control = NULL;
29     msg.msg_controllen = 0;
30     /* Save some cycles and don‘t copy the address if not needed */
31     /* 地址结构信息 */
32     msg.msg_name = addr ? (struct sockaddr *)&address : NULL;
33     /* We assume all kernel code knows the size of sockaddr_storage */
34     msg.msg_namelen = 0;
35     msg.msg_iocb = NULL;
36     msg.msg_flags = 0;
37
38     /* 非阻塞标记 */
39     if (sock->file->f_flags & O_NONBLOCK)
40         flags |= MSG_DONTWAIT;
41
42     /* 接收消息 */
43     err = sock_recvmsg(sock, &msg, flags);
44
45     /* 拷贝地址到用户空间 */
46     if (err >= 0 && addr != NULL) {
47         err2 = move_addr_to_user(&address,
48                      msg.msg_namelen, addr, addr_len);
49         if (err2 < 0)
50             err = err2;
51     }
52
53     fput_light(sock->file, fput_needed);
54 out:
55     return err;
56 }

tcp_rcvmsg的实现,请移步<TCP层recvmsg系统调用的实现分析>;

原文地址:https://www.cnblogs.com/wanpengcoder/p/11749319.html

时间: 2024-08-30 09:27:20

套接字之recvfrom系统调用的相关文章

套接字之recv系统调用

recv系统调用对sys_recvfrom进行了简单的封装,只是其中不包含地址信息,其只需要从建立连接的另一端接收信息: 1 /* 2 * Receive a datagram from a socket. 3 */ 4 5 SYSCALL_DEFINE4(recv, int, fd, void __user *, ubuf, size_t, size, 6 unsigned int, flags) 7 { 8 return sys_recvfrom(fd, ubuf, size, flags,

套接字之send系统调用

send系统调用只是对sendto系统调用进行了封装,传递的参数不包含目的地址信息,数据会发送到已经建立连接的另一端的地址: 1 /* 2 * Send a datagram down a socket. 3 */ 4 5 SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, 6 unsigned int, flags) 7 { 8 return sys_sendto(fd, buff, len, flags, NULL

套接字之close系统调用

close系统调用用于关闭文件描述符,其系统调用实现如下所示: 1 / 2 * Careful here! We test whether the file pointer is NULL before 3 * releasing the fd. This ensures that one clone task can't release 4 * an fd while another clone is opening it. 5 */ 6 SYSCALL_DEFINE1(close, unsi

套接字之sendmsg系统调用

sendmsg系统调用允许在用户空间构造消息头和控制信息,用此函数可以发送多个数据缓冲区的数据,并支持控制信息:当调用进入内核后,会将用户端的user_msghdr对应拷贝到内核的msghdr中,然后进行数据发送: 1 SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags) 2 { 3 /* 不支持64位采用32位兼容标记 */ 4 if (flags & MSG_CMSG_

套接字之sendto系统调用

sendto系统调用用于向指定的目的地址发送数据,其系统调用的流程比较容易理解,如下面所示,其主要完成 (1)将用户数据组织成msghdr,(2)而后调用socket操作的sendmsg:ipv4对应的sendmsg实现为inet_sendmsg,该函数进行端口自动绑定检查和绑定后,调用传输层的sendmsg函数发送数据,比如tcp会调用tcp_sendmsg函数,这里不详细介绍,读到tcp模块在进行补充: 1 /* 2 * Send a datagram to a given address.

套接字之recvmsg系统调用

recvmsg系统调用允许用户指定msghdr结构来接收数据,可以将数据接收到多个缓冲区中,并且可以接收控制信息:接收信息过程与其他接收系统调用核心一致,都是调用传输层的接收函数进行数据接收: 1 SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg, 2 unsigned int, flags) 3 { 4 /* 不支持64位采用32位兼容标记 */ 5 if (flags & MSG_CMSG_COMPAT) 6

套接字之select系统调用

select是IO多路复用的一种方式,用来等待一个列表中的多个描述符的可读可写状态: 1 SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp, 2 fd_set __user *, exp, struct timeval __user *, tvp) 3 { 4 struct timespec64 end_time, *to = NULL; 5 struct timeval tv; 6 int r

套接字之msghdr结构

用户端在使用sendmsg/recvmsg发送或者接收数据时,会使用msghdr来构造消息,其对应的内核结构为user_msghdr:其中msg_iov向量指向了多个数据区,msg_iovlen标识了数据区个数:在通过系统调用进入内核后,该结构中的信息会拷贝给内核的msghdr结构: 1 /* 用户空间的消息头 */ 2 struct user_msghdr { 3 /* 指向地址结构 */ 4 void __user *msg_name; /* ptr to socket address st

Linux网络编程——原始套接字实例:简单版网络数据分析器

通过<Linux网络编程--原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 MAC 头部(有线局域网) 注意:CRC.PAD 在组包时可以忽略 链路层数据包的其中一种情况: unsigned char msg[1024] = { //--------------组MAC--------14------ 0xb8, 0x88, 0xe3, 0xe1, 0x10, 0xe6, // dst