send、sendto与sys_sendto之间的关系

来源:互联网 发布:网络大电影演员成本 编辑:程序博客网 时间:2024/05/27 00:31

sys_sendto()

sys_socketcall() --> sys_sendto()

asmlinkage long sys_sendto(
           int                    fd, 
           void __user            *buff, size_t len, 
           unsigned               flags,
           struct sockaddr __user *addr, int     addr_len)
{
    struct socket *sock;
    char          address[MAX_SOCK_ADDR];
    int           err;
    struct msghdr msg;
    struct iovec iov;
    int           fput_needed;
    struct file   *sock_file;

    sock_file = fget_light(fd, &fput_needed);
    err = -EBADF;
    if (!sock_file)
        goto out;

    sock = sock_from_file(sock_file, &err);
    if (!sock)
        goto out_put;
    iov.iov_base = buff;
    iov.iov_len = len;
    msg.msg_name = NULL;
    msg.msg_iov = &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, address);
        if (err < 0)
            goto out_put;
        msg.msg_name = address;
        msg.msg_namelen = addr_len;
    }
    if (sock->file->f_flags & O_NONBLOCK)
        flags |= MSG_DONTWAIT;
    msg.msg_flags = flags;
    err = sock_sendmsg(sock, &msg, len);

out_put:
    fput_light(sock_file, fput_needed);
out:
    return err;
}

在内核的实现中,send和sendto系统调用最终都会调用到内核函数:

    asmlinkage long sys_sendto(
           int                    fd, 
           void __user            *buff, size_t len, 
           unsigned               flags,
           struct sockaddr __user *addr, int     addr_len)

    fd       socket文件描述符
    buff     指向需要发送的数据
    len      需要发送的数据的长度
    flags    标志位
    addr     数据报文要发送的对方端点的地址信息
    addr_len 地址信息的长度


    在send系统调用中,参数addr被置为NULL,addr_len为0。sys_sendto首先根据传入的描述符fd,找到对应的struct socket结构体。然后构建内核的消息结构struct msghdr:
内核的消息结构struct--msghdr:
    struct msghdr {
        void             *msg_name;
        int              msg_namelen;
        struct iovec     *msg_iov;
        __kernel_size_t -msg_iovlen;
        void             *msg_control;
        __kernel_size_t -msg_controllen;
        unsigned         msg_flags;
    };

msghdr->msg_name
msghdr->msg_namelen
-----------------------------------
    msg_name和msg_namelen就是数据报文要发向的对端的地址信息(即sendto系统调用中的addr和addr_len)。当使用send时,它们的值为NULL和0。

msghdr->msg_iov
-----------------------------------
    msg_iov的定义如下:
    struct--iovec {
        void __user     *iov_base;
        __kernel_size_t iov_len;
    };
    表示存放待发送数据的一个缓冲区,iov_base是缓冲区的起始地址,指向message, iov_len是缓冲区的长度,指向length。

msghdr->msg_iovlen
-----------------------------------
    msg_iovlen是缓冲区的数量,对于sendto和send来讲,msg_iovlen都是1。 

msghdr->msg_flags
msghdr->msg_control
msghdr->msg_controllen
-----------------------------------
    msg_flags即为传入的参数flags,现在暂时不过多的关注flags的应用。
    msg_control和msg_controllen暂时不关注。

    sys_sendto构建完这些后,调用sock_sendmsg继续执行发送流程,传入参数为struct msghdr和数据的长度。忽略中间的一些不重要的细节,sock_sendmsg继续调用__sock_sendmsg(),__sock_sendmsg()最后调用struct socket->ops->sendmsg,即对应套接字类型的sendmsg()函数,所有的套接字类型的sendmsg()函数都是inet_sendmsg(),该函数首先检查本地端口是否已绑定,无绑定则执行自动绑定,而后调用具体协议的sendmsg函数。
原创粉丝点击