• 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. };  
     
     
  • 相关阅读:
    组装query,query汇总,query字段
    POJ 1276, Cash Machine
    POJ 1129, Channel Allocation
    POJ 2531, Network Saboteur
    POJ 1837, Balance
    POJ 3278, Catch That Cow
    POJ 2676, Sudoku
    POJ 3126, Prime Path
    POJ 3414, Pots
    POJ 1426, Find The Multiple
  • 原文地址:https://www.cnblogs.com/feng9exe/p/7001332.html
Copyright © 2020-2023  润新知