#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int s, void*buf, size_t len , int flags, struct sockaddr*from , socklen_t *fromlen);
第1个参数s代表正在监听的端口的套接口文件描述符,它是由函数socket()生成的
第2个参数buff表示接收数据缓冲区, 接收到的数据将放在这个指针所指向的内存空间中
第3个参数len表示接收数据缓冲区大小,系统根据这个值来确保接收缓冲区的安全,防止溢出
第4个参数from是指向本地的数据结构sockaddr_in 的指针,发送数据时发送方的地址信息放在这个结构中
第5个参数fromlen表示第4个参数的所指内容的长度,可以使用sizeof(struct sockaddr_in)来获得。
当函数陷入内核中时,执行long sys_recvfrom(int fd, , void __user *ubuf, size_t size, int __user*addr_len)
系统调用函数sys_recvfrom主要查找文件描述符对应的内核socket结构,建立一个消息结构,将用户空间的地址缓冲区指针和数据缓冲区指针打包到消息队列中,在套接字文件描述符对应的数据链中查找对应的数据,将数据复制到消息中,销毁数据链中的数据,将数据复制到应用层的空间中, 减少文件描述符的引用计数。
sys_recvfrom()调用函数 sockfd_lookup_light() 查找到文件描述符对应的内核,socket结构后,会申请一块内存空间来保存链接成功的客户端状态,socket结构的一些参数,例如类型type操作方式ops等会继承服务器原来的值,例如原来服务器的类型为AF——INET则其操作模式仍然为af_inet.c文件中的各个函数,然后会查找到文件描述符表,获得一个新的结构对应的文件描述符。
在内核中使用一个消息结构msghdr用来存放所有的数据结构,其原型如下:
struct msghdr{
void *msg_name; //socket名称
int msg_namelen; //socket名称的长度
struct iovec* msg_iov; //向量,存放数据
__kernel_size_t msg_iovlen;//向量数量
void *msg_control;
__kernel_size_t msg_controllen;//msg_control的数量
unsigned msg_flags; //消息选项
};
对于AF——INET 族,recvfrom对应于udp_recvmsg()函数,其实现在文件af_inet.c 中,
1接收数据报数据,。在接收的时候根据设置超时来确定是否要一直等待。
2计算复制出的数据长度,当街收到的数据长度比用户缓冲区的长度大时。设置MSG——MSG_TRUNC标志方便下次的复制
3将数据复制到用户缓冲区空间中。
4复制发送方的地址和协议族
5根据消息结构的标志设置,接收其他的信息,
6销毁数据报缓冲区对应的变量。