zoukankan      html  css  js  c++  java
  • linux内核中的文件描述符(二)--socket和文件描述符

    http://blog.csdn.net/ce123_zhouwei/article/details/8459730

     Linux内核中的文件描述符(二)--socket和文件描述符

    Kernel version:2.6.14

    CPU architecture:ARM920T

    Author:ce123(http://blog.csdn.NET/ce123)

    socket和文件系统紧密相关,我们可以通过文件系统的open、read、write和close等操作socket。下面是一个简单的例子。

    [plain] view plain copy
     print?
    1. /****************************************************************************/  
    2. /*简介:TCPServer示例 */  
    3. /****************************************************************************/  
    4. #include <stdlib.h>   
    5. #include <stdio.h>   
    6. #include <errno.h>   
    7. #include <string.h>   
    8. #include <netdb.h>   
    9. #include <sys/types.h>   
    10. #include <netinet/in.h>   
    11. #include <sys/socket.h>   
    12. int main(int argc, char *argv[])   
    13. {   
    14.  int sockfd,new_fd;   
    15.  struct sockaddr_in server_addr;   
    16.  struct sockaddr_in client_addr;   
    17.  int sin_size,portnumber;   
    18.  const char hello[]="Hello ";  
    19.   
    20.  if(argc!=2)   
    21.   {   
    22.      fprintf(stderr,"Usage:%s portnumbera ",argv[0]);   
    23.      exit(1);   
    24.   }   
    25.   if((portnumber=atoi(argv[1]))<0)   
    26.   {   
    27.       fprintf(stderr,"Usage:%s portnumbera ",argv[0]);   
    28.       exit(1);   
    29.  }   
    30.   /* 服务器端开始建立socket描述符 */   
    31.   if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)   
    32.   {   
    33.      fprintf(stderr,"Socket error:%s a",strerror(errno));   
    34.      exit(1);   
    35.   }   
    36.   /* 服务器端填充 sockaddr结构 */   
    37.   bzero(&server_addr,sizeof(struct sockaddr_in));   
    38.   server_addr.sin_family=AF_INET;   
    39.   server_addr.sin_addr.s_addr=htonl(INADDR_ANY);   
    40.   server_addr.sin_port=htons(portnumber);   
    41.   /* 捆绑sockfd描述符 */   
    42.   if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==   
    43.   -1)   
    44.   {   
    45.      fprintf(stderr,"Bind error:%s a",strerror(errno));   
    46.      exit(1);   
    47.   }   
    48.   /* 监听sockfd描述符 */   
    49.   if(listen(sockfd,5)==-1)   
    50.   {   
    51.       fprintf(stderr,"Listen error:%s a",strerror(errno));   
    52.       exit(1);   
    53.   }   
    54.   while(1)   
    55.   {   
    56.   /* 服务器阻塞,直到客户程序建立连接 */   
    57.    sin_size=sizeof(struct sockaddr_in);   
    58.    if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)   
    59.      {   
    60.       fprintf(stderr,"Accept error:%s a",strerror(errno));   
    61.       exit(1);   
    62.      }   
    63.    fprintf(stderr,"Server get connection from %s ",   
    64.    inet_ntoa(client_addr.sin_addr));   
    65.    if(write(new_fd,hello,strlen(hello))==-1)   
    66.    {   
    67.       fprintf(stderr,"Write Error:%s ",strerror(errno));   
    68.       exit(1);   
    69.     }   
    70.      /* 这个通讯已经结束 */   
    71.       close(new_fd);   
    72.   /* 循环下一个 */   
    73.   }   
    74.   close(sockfd);   
    75.   exit(0);   
    76. }  

    下图说明了socket和fd是怎样联系起来的。

    下面通过来具体分析一下。sys_socket是socket相关函数的总入口。

     

    [plain] view plain copy
     print?
    1. net/socket.c  
    2. /*  
    3.  *  System call vectors.   
    4.  *  
    5.  *  Argument checking cleaned up. Saved 20% in size.  
    6.  *  This function doesn't need to set the kernel lock because  
    7.  *  it is set by the callees.   
    8.  */  
    9.   
    10. asmlinkage long sys_socketcall(int call, unsigned long __user *args)  
    11. {  
    12.     unsigned long a[6];  
    13.     unsigned long a0,a1;  
    14.     int err;  
    15.   
    16.     if(call<1||call>SYS_RECVMSG)  
    17.         return -EINVAL;  
    18.   
    19.     /* copy_from_user should be SMP safe. */  
    20.     if (copy_from_user(a, args, nargs[call]))  
    21.         return -EFAULT;  
    22.   
    23.     err = audit_socketcall(nargs[call]/sizeof(unsigned long), a);  
    24.     if (err)  
    25.         return err;  
    26.   
    27.     a0=a[0];  
    28.     a1=a[1];  
    29.       
    30.     switch(call)   
    31.     {  
    32.         case SYS_SOCKET:  
    33.             err = sys_socket(a0,a1,a[2]);  
    34.             break;  
    35.         case SYS_BIND:  
    36.             err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]);  
    37.             break;  
    38.         case SYS_CONNECT:  
    39.             err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);  
    40.             break;  
    41.         case SYS_LISTEN:  
    42.             err = sys_listen(a0,a1);  
    43.             break;  
    44.         case SYS_ACCEPT:  
    45.             err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);  
    46.             break;  
    47.         case SYS_GETSOCKNAME:  
    48.             err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);  
    49.             break;  
    50.         case SYS_GETPEERNAME:  
    51.             err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]);  
    52.             break;  
    53.         case SYS_SOCKETPAIR:  
    54.             err = sys_socketpair(a0,a1, a[2], (int __user *)a[3]);  
    55.             break;  
    56.         case SYS_SEND:  
    57.             err = sys_send(a0, (void __user *)a1, a[2], a[3]);  
    58.             break;  
    59.         case SYS_SENDTO:  
    60.             err = sys_sendto(a0,(void __user *)a1, a[2], a[3],  
    61.                      (struct sockaddr __user *)a[4], a[5]);  
    62.             break;  
    63.         case SYS_RECV:  
    64.             err = sys_recv(a0, (void __user *)a1, a[2], a[3]);  
    65.             break;  
    66.         case SYS_RECVFROM:  
    67.             err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],  
    68.                        (struct sockaddr __user *)a[4], (int __user *)a[5]);  
    69.             break;  
    70.         case SYS_SHUTDOWN:  
    71.             err = sys_shutdown(a0,a1);  
    72.             break;  
    73.         case SYS_SETSOCKOPT:  
    74.             err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);  
    75.             break;  
    76.         case SYS_GETSOCKOPT:  
    77.             err = sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]);  
    78.             break;  
    79.         case SYS_SENDMSG:  
    80.             err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]);  
    81.             break;  
    82.         case SYS_RECVMSG:  
    83.             err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]);  
    84.             break;  
    85.         default:  
    86.             err = -EINVAL;  
    87.             break;  
    88.     }  
    89.     return err;  
    90. }   /* It may be already another descriptor 8) Not kernel problem. */  
    91.     return retval;  
    92.   
    93. out_release:  
    94.     sock_release(sock);  
    95.     return retval;  
    96. }  
    当应用程序使用socket()创建一个socket时,会执行sys_socket,其定义如下

     

    [plain] view plain copy
     print?
    1. asmlinkage long sys_socket(int family, int type, int protocol)  
    2. {  
    3.     int retval;  
    4.     struct socket *sock;  
    5.   
    6.     retval = sock_create(family, type, protocol, &sock);//创建socket  
    7.     if (retval < 0)  
    8.         goto out;  
    9.   
    10.     retval = sock_map_fd(sock);//分配一个未使用的文件描述符fd,并将socket和fd建立联系  
    11.     if (retval < 0)  
    12.         goto out_release;  
    13.   
    14. out:  
    15.     /* It may be already another descriptor 8) Not kernel problem. */  
    16.     return retval;  
    17.   
    18. out_release:  
    19.     sock_release(sock);  
    20.     return retval;  
    21. }  
    结构体socket的定义如下(includelinux et.h):

     

    [plain] view plain copy
     print?
    1. struct socket {  
    2.     socket_state        state;  
    3.     unsigned long       flags;  
    4.     struct proto_ops    *ops;  
    5.     struct fasync_struct    *fasync_list;  
    6.     struct file     *file;//通过这个和文件描述符建立联系  
    7.     struct sock     *sk;  
    8.     wait_queue_head_t   wait;  
    9.     short           type;  
    10. };  
    下面我们再来看看sock_map_fd函数

     

    [plain] view plain copy
     print?
    1. int sock_map_fd(struct socket *sock)  
    2. {  
    3.     int fd;  
    4.     struct qstr this;  
    5.     char name[32];  
    6.   
    7.     /*  
    8.      *  Find a file descriptor suitable for return to the user.   
    9.      */  
    10.   
    11.     fd = get_unused_fd();//分配一个未使用的fd  
    12.     if (fd >= 0) {  
    13.         struct file *file = get_empty_filp();  
    14.   
    15.         if (!file) {  
    16.             put_unused_fd(fd);  
    17.             fd = -ENFILE;  
    18.             goto out;  
    19.         }  
    20.   
    21.         this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);  
    22.         this.name = name;  
    23.         this.hash = SOCK_INODE(sock)->i_ino;  
    24.   
    25.         file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);  
    26.         if (!file->f_dentry) {  
    27.             put_filp(file);  
    28.             put_unused_fd(fd);  
    29.             fd = -ENOMEM;  
    30.             goto out;  
    31.         }  
    32.         file->f_dentry->d_op = &sockfs_dentry_operations;  
    33.         d_add(file->f_dentry, SOCK_INODE(sock));  
    34.         file->f_vfsmnt = mntget(sock_mnt);  
    35.         file->f_mapping = file->f_dentry->d_inode->i_mapping;  
    36.   
    37.         sock->file = file;//建立联系  
    38.         file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;//socket操作函数,当使用文件系统的IO函数时,其实使用的是socket的IO函数  
    39.         file->f_mode = FMODE_READ | FMODE_WRITE;  
    40.         file->f_flags = O_RDWR;  
    41.         file->f_pos = 0;  
    42.         file->private_data = sock;  
    43.         fd_install(fd, file);  
    44.     }  
    45.   
    46. out:  
    47.     return fd;  
    48. }  
    49.   
    50. static struct file_operations socket_file_ops = {  
    51.     .owner =    THIS_MODULE,  
    52.     .llseek =   no_llseek,  
    53.     .aio_read = sock_aio_read,  
    54.     .aio_write =    sock_aio_write,  
    55.     .poll =     sock_poll,  
    56.     .unlocked_ioctl = sock_ioctl,  
    57.     .mmap =     sock_mmap,  
    58.     .open =     sock_no_open,   /* special open code to disallow open via /proc */  
    59.     .release =  sock_close,  
    60.     .fasync =   sock_fasync,  
    61.     .readv =    sock_readv,  
    62.     .writev =   sock_writev,  
    63.     .sendpage = sock_sendpage  
    64. };  
     
     
  • 相关阅读:
    一、JDBC操作
    十五、时间日期类
    十四、字符串详解
    源文件
    十六、·实现显示所有雇员
    十五、抽象出基础接口
    十四、增加EmployeeService实现用户添加
    十三、解决懒加载
    python __new__以及__init__
    Python的getattr(),setattr(),delattr(),hasattr()及类内建__getattr__应用
  • 原文地址:https://www.cnblogs.com/feng9exe/p/7001332.html
Copyright © 2011-2022 走看看