应用层
<h2>概述</h2>
<p>1、send 系统调用,先根据 fd 找到对应的 socket,然后调用 <code>sock-&gt;ops-&gt;sendmsg()</code>,对于 TCP 而言,则是 <code>inet_sendmsg</code></p>
<h2>分析</h2>
<p>应用层调用 send,对应的代码:</p>
<pre><code class="language-c">// file: net/socket.c
/*
* Send a datagram down a socket.
*/
SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len,
unsigned int, flags)
{
return sys_sendto(fd, buff, len, flags, NULL, 0);
}
/*
* Send a datagram to a given address. We move the address into kernel
* space and check the user space data area is readable before invoking
* the protocol.
*/
SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
unsigned int, flags, struct sockaddr __user *, addr,
int, addr_len)
{
struct socket *sock;
struct sockaddr_storage address;
int err;
struct msghdr msg;
struct iovec iov;
int fput_needed;
if (len &gt; INT_MAX)
len = INT_MAX;
sock = sockfd_lookup_light(fd, &amp;err, &amp;fput_needed); // 根据 fd 找到 socket
if (!sock)
goto out;
iov.iov_base = buff;
iov.iov_len = len;
msg.msg_name = NULL;
msg.msg_iov = &amp;iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_namelen = 0;
if (addr) {
err = move_addr_to_kernel(addr, addr_len, &amp;address);
if (err &lt; 0)
goto out_put;
msg.msg_name = (struct sockaddr *)&amp;address;
msg.msg_namelen = addr_len;
}
if (sock-&gt;file-&gt;f_flags &amp; O_NONBLOCK)
flags |= MSG_DONTWAIT;
msg.msg_flags = flags;
err = sock_sendmsg(sock, &amp;msg, len); // 进一步调用
out_put:
fput_light(sock-&gt;file, fput_needed);
out:
return err;
}
int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
{
struct kiocb iocb;
struct sock_iocb siocb;
int ret;
init_sync_kiocb(&amp;iocb, NULL);
iocb.private = &amp;siocb;
ret = __sock_sendmsg(&amp;iocb, sock, msg, size);
if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&amp;iocb);
return ret;
}
EXPORT_SYMBOL(sock_sendmsg);
static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size)
{
int err = security_socket_sendmsg(sock, msg, size);
return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size);
}
static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size)
{
struct sock_iocb *si = kiocb_to_siocb(iocb);
si-&gt;sock = sock;
si-&gt;scm = NULL;
si-&gt;msg = msg;
si-&gt;size = size;
return sock-&gt;ops-&gt;sendmsg(iocb, sock, msg, size); // 对于 TCP 而言,socket-&gt;ops = inet_stream_ops。sendmsg = inet_sendmsg
}
</code></pre>