套接字之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系统调用的实现分析>;

posted @ 2019-10-27 21:55  AlexAlex  阅读(1218)  评论(0编辑  收藏  举报