实现发送系统调用
传输层传输处理
复制传输层
传输层传输
网络层传输处理
相邻子系统
网络设备子系统
fec 网卡驱动发送
总结
实现发送系统调用
send 系统调用的源代码位于文件net/socket.c 中。这个系统调用实际上内部使用了sendto系统调用。我主要做了两件事:
找到内核中实际的套接字,并记录该对象内各个协议栈的函数地址。
构造一个struct msghdr 对象并加载用户传递的任何数据,例如缓冲区地址和数据长度。
//net/socket.c
SYSCALL_DEFINE4(发送,整数
、fd、无效
__user *,buff,size_t
, Len, 未签名
整数
,标志){返回
sys_sendto(fd, buff, len, 标志,
, 0
);}SYSCALL_DEFINE6(.){//1 根据fd查找socket。
sock=sockfd_lookup_light(fd, err, fput_needed); //2.
结构
姆斯格哈德
信息
;
结构
约贝克
车联网
;
iov.iov_base=缓冲区;iov.iov_len=msg.msg_iovlen=1
; msg.msg_iov=iov; msg.msg_flags=标志;
sock_sendmsg(sock, msg, len);} 从源码中可以看到,用户态下使用的send和sendto函数实际上都是通过sendto系统调用来实现的。 (send以方便调用的方式方便地封装。)
sendto系统调用首先根据用户传递的fd句柄号查找实际的socket内核对象。然后将用户请求的所有buff、len、flag 和其他参数打包到struct msghdr 对象中。然后调用sock_sendmsg=__sock_sendmsg==__sock_sendmsg_nosec 。在__sock_sendmsg_nosec中,调用从系统调用进入协议栈。我们来看看它的源代码。
//net/socket.c
静止的
排队
整数
__sock_sendmsg_nosec(.){ .返回
sock-ops-sendmsg(iocb, sock, msg, size);} 这里调用的是sock-ops-sendmsg,实际执行的是inet_sendmsg。 (inet_sendmsg函数的地址是通过socket内核对象的ops成员找到的。该函数是AF_INET协议族提供的通用发送函数。)
一般流程如图所示。
传输层传输处理
复制传输层
进入协议栈inet_sendmsg后,内核找到套接字上特定的协议发送函数。对于TCP 协议,它是tcp_sendmsg,对于UPD,它是udp_sendmsg(也可以通过套接字内核对象找到)。
在此函数中,内核为内核状态申请skb 内存,并将用户发送的数据复制到其中。请注意,如果不满足发送条件,则此时可能不会真正开始发送。大致流程如下: