• 首页
  •   Leopard|  系统群乐|  Vista系统|  Linux系统|  Mac系统|  其它操作系统|
    您现在的位置 主页>Linux系统>

    读核日记socket篇

    来源:每天在线工程有限公司 | 更新日期:2009-01-07
    关键字:,,

    今天被一个sock_fd的值的问题折磨了半天

    靠,干脆花了1个小时看了一下内核

    貌似效果不错,做个笔记

    pblog的缩进还挺麻烦的,不管它了

    可以直接找我要文件,如果看起来不爽的话

    /*
    网络编程中要注意描述符的边界问题

    比如socket描述符等

    描述符等于0的情况也是正常的

    if (sock >= 0) //应该按照 sock >= 0的情况来判断
     ...

    如果是
    if (sock > 0)
     ... //可能出现的问题是,tcp连接不能建立,包不能正确传送或者不能传送
     
    值为0属于正常情况

    我考,看socket源代码,日

    socket也是加入系统标用表中的系统函数,参考 /kernel/sys.c
    */

    // /net/core/sock.c
    // /net/socket.c

    /* 入口函数 sys_socket();
     * 原型: asmlinkage long sys_socket(int family, int type, int protocol);
     * 调用函数 socket();
     * 原型: int socket(int domain, int type, int protocol);
     * 两者应该是对应起来的
     * 取值范围
     * 参考 /include/linux/socket.h address family的两组宏定义 */
    asmlinkage long sys_socket(int family, int type, int protocol)
    {
     int retval;
     struct socket *sock;

     //创建socket,由此可以看出socket是非负整数值
     retval = sock_create(family, type, protocol, &sock);
     if (retval < 0)
      goto out;

     //加入描述符表,呵呵
     retval = sock_map_fd(sock);
     if (retval < 0)
      goto out_release; //这会已经分配了socket,所以返回前要释放资源

    out:
     /* It may be already another descriptor 8) Not kernel problem. */
     // 正常返回,创建失败返回
     return retval;

    out_release:
     sock_release(sock);
     return retval;
    }

    /* sock_create 最终调用到 函数 __sock_create()
     * 函数名字前面加两个dash的表示系统内部函数
     *
     *
     */
    static int __sock_create(int family, int type, int protocol, struct socket **res, int kern)
    {
     int i;
     int err;
     struct socket *sock;

     /*
      * Check protocol is in range
      */
     if (family < 0 || family >= NPROTO)
      return -EAFNOSUPPORT;
     if (type < 0 || type >= SOCK_MAX)
      return -EINVAL;

     /* Compatibility.

        // ugly 丑陋的
        // moron 低能,白痴
        // 避免加载模块时死锁
        This uglymoron is moved from INET layer to here to avoid
        deadlock in module load.
      */
     // 协议族参考 /include/asm-i386/socket.h
     if (family == PF_INET && type == SOCK_PACKET) {//PF_INET == AF_INET --> Internet IP Protocol
      static int warned;
      if (!warned) {
       warned = 1;
       printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)n", current->comm);
      }
      family = PF_PACKET; //packet family
     }

            //是否和filter结合在一起的? 
     err = security_socket_create(family, type, protocol, kern);
     if (err)
      return err;
      
    #if defined(CONFIG_KMOD)
     /* Attempt to load a protocol module if the find failed.
      *
      * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
      * requested real, full-featured networking support upon configuration.
      * Otherwise module support will break!
      */
     if (net_families[family]==NULL)
     {
      request_module("net-pf-%d",family);
     }
    #endif

     net_family_read_lock();
     if (net_families[family] == NULL) {
      i = -EAFNOSUPPORT;
      goto out;
     }

    /*
     * Allocate the socket and allow the family to set things up. if
     * the protocol is 0, the family is instructed to select an appropriate
     * default.
     */
            //分配资源,日哦,分配inode
     if (!(sock = sock_alloc()))
     {
      printk(KERN_WARNING "socket: no more socketsn");
      i = -ENFILE;  /* Not exactly a match, but its the
            closest posix thing */
      goto out;
     }

     //赋值啦
     sock->type  = type;

     //refcnt 引用计数器
     /*
      * We will call the ->create function, that possibly is in a loadable
      * module, so we have to bump that loadable module refcnt first.
      */
     i = -EAFNOSUPPORT;
     if (!try_module_get(net_families[family]->owner))
      goto out_release;

     if ((i = net_families[family]->create(sock, protocol)) < 0)
      goto out_module_put;
     /*
      * Now to bump the refcnt of the [loadable] module that owns this
      * socket at sock_release time we decrement its refcnt.
      */
     if (!try_module_get(sock->ops->owner)) {
      sock->ops = NULL;
      goto out_module_put;
     }
     /*
      * Now that we're done with the ->create function, the [loadable]
      * module can have its refcnt decremented
      */
     module_put(net_families[family]->owner);
     *res = sock;
     security_socket_post_create(sock, family, type, protocol, kern);

    out:
     net_family_read_unlock();
     return i;
    out_module_put:
     module_put(net_families[family]->owner);
    out_release:
     sock_release(sock);
     goto out;
    }

    /*
     * Obtains the first available file descriptor and sets it up for use.
     * 取得第一个可用的描述符,并设置给它,它就是我们的返回值
     * This function creates file structure and maps it to fd space
     * of current process. On success it returns file descriptor
     * 为当前进程建立并映射文件描述符,成功返回描述符,值保存在sock->file中
     * and file struct implicitly stored in sock->file.
     * Note that another thread may close file descriptor before we return
     * from this function. We use the fact that now we do not refer
     * to socket after mapping. If one day we will need it, this
     * function will increment ref. count on file by 1.
     * 其他线程在函数返回之前可能关闭描述符,因此映射之后我们并不socket(靠,这是什么意思
     * 只建立并映射socket,但不是可用的?,日),在我们需要调用到描述符的时候
     * 对引用计数器加1
     * In any case returned fd MAY BE not valid!
     * 任何情况下返回文件描述符可能都是无效的
     * This race condition is unavoidable
     * with shared fd spaces, we cannot solve it inside kernel,
     * 这种竞争情况无可避免(指不同线程对文件描述符操作的竞争),在内核中这个问题不能解决
     * but we take care of internal coherence yet. //这个不好翻译
     */
     
    int sock_map_fd(struct socket *sock)
    {
     int fd;
     /*
       * "quick string" -- eases parameter passing, but more importantly
       * saves "metadata" about the string (ie length and the hash).
       *
       * hash comes first so it snuggles against d_parent and d_bucket in the
       * dentry.
       * struct qstr {
      * unsigned int hash;
      * const unsigned char *name;
      * unsigned int len;
      * };
       */
     struct qstr this;
     char name[32];

     /*
      * Find a file descriptor suitable for return to the user.
      */

     //取得第一个可用的文件描述符
     fd = get_unused_fd();
     if (fd >= 0) {//成功
      struct file *file = get_empty_filp();//取得一个可用的文件结构

      if (!file) {//没有取得
       put_unused_fd(fd); //释放文件描述符
       fd = -ENFILE;
       goto out;
      }

      sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
      this.name = name;
      this.len = strlen(name);
      this.hash = SOCK_INODE(sock)->i_ino;

      //日,这里又分配什么?
      file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
      if (!file->f_dentry) {//失败
       put_filp(file);
       put_unused_fd(fd);
       fd = -ENOMEM;
       goto out;
      }
      file->f_dentry->d_op = &sockfs_dentry_operations;
      d_add(file->f_dentry, SOCK_INODE(sock));
      file->f_vfsmnt = mntget(sock_mnt);//原语操作
      file->f_mapping = file->f_dentry->d_inode->i_mapping;

      sock->file = file;
      file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
      file->f_mode = FMODE_READ | FMODE_WRITE;
      file->f_flags = O_RDWR;
      file->f_pos = 0;
      fd_install(fd, file);//安装文件描述符
     }

    out:
     return fd;
    }


    随机推荐
    图文推荐
    ©2008 医院皮肤科 ,, 24小时健康咨询热线
    医院概况 | 联系我们 | 网站地图 |在线咨询 | QQ咨询| RSS