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