Chinaunix首页 | 论坛 | 博客
  • 博客访问: 150103
  • 博文数量: 34
  • 博客积分: 2000
  • 博客等级: 大尉
  • 技术积分: 410
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-03 09:44
文章分类

全部博文(34)

文章存档

2011年(1)

2008年(33)

我的朋友

分类: LINUX

2008-07-17 11:03:59

我们只以其中一个接口write为线索,对套接字写(网络数据发送)的流程进行分析。系统调用
write会调用内核函数sys_write,sys_write调用vfs_write完成实际的写操作。
    vfs_write会先调用file->f_op->write(file从套接字描述符获得)。如果file->f_op-> write不存在,则调用do_sync_write。该函数会调用sock_aio_write,
sock_aio_write又会调用 __sock_sendmsg,然后到myinet_sendmsg,最后才到sk->sk_prot->sendmsg,对于RAW协议来讲,即myraw_sendmsg。
    sock_aio_write的函数原型如下:
        static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
                      size_t size, loff_t pos)
ubuf是用户待发送数据,size是数据长度,pos是文件位置(永远为零)。在这个函数里,会把用户待发送数据封装成一个struct msghdr结构:
        struct msghdr {
            void    *   msg_name;   /* Socket name          */
            int     msg_namelen;    /* Length of name       */
            struct iovec *  msg_iov;    /* Data blocks          */
            __kernel_size_t msg_iovlen; /* Number of blocks     */
            void    *   msg_control;    /* Per protocol magic (eg BSD file descriptor passing) */
            __kernel_size_t msg_controllen; /* Length of cmsg list */
            unsigned    msg_flags;
        };
    如果用户代码为: write(fd, "abcdef", 6 ),则在sock_aio_write中封装成的msghdr结构为:
        struct msghdr thehdr{
            .msg_name = NULL,
            .msg_namelen = 0,
            .msg_iov.iov_base = "abcdef",
            .msg_iov.iov_len = 6,
            .msg_iovlen = 1,
            .msg_control = NULL,
            .msg_controllen = 0,
            .msg_flags = 0
        };
    raw_sendmsg的函数原型为:
        static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                                    size_t len)
所以,它拿到的是已经封装好的消息msg。该函数所做的第一件事情是检查len,其最大长度是16位(0xffff),然后,确认msg->msg_flags中没有MSG_OOB(RAW不支持带外数据的发送
)。
    如果msg->msg_namelen不等于零,则name中存储的是域和目的地址的信息,如果等于零,则当前必须是已经建立了TCP连接的,否则数据不知道发往哪儿。
    接下来,查看控制数据缓冲区长度是否为零,如果不是,则有控制信息msg->msg_control,调用ip_cmsg_send发送控制信息(实际上,主要是填充一个结构体struct
ipcm_cookie ipc,从代码来看,该结构应该用于构建ip头)。
    inet->hdrincl表示需要自己来构建ip头,所以如果inet->hdrincl==1,并且,ipc->opt!=NULL则返回出错信息:无效参数。
    接下来判断目的地址是否为组播地址(组播地址的最高四位为1110),是则作相应处理。
    接下来,声明并初始化一个struct flowi结构,如果不是自己构建ip头,则调用raw_probe_proto_opt
    接下来的内容,暂时未能很好理解,留待下文分析。
阅读(2071) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~