×
单片机 > 单片机程序设计 > 详情

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

发布时间:2020-08-31 发布时间:
|
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    
  5. #include    
  6. #include    
  7. #include    
  8. #include    
  9. #include    
  10. #include    
  11. #include    
  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\n";  
  19.   
  20.  if(argc!=2)   
  21.   {   
  22.      fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);   
  23.      exit(1);   
  24.   }   
  25.   if((portnumber=atoi(argv[1]))<0)   
  26.   {   
  27.       fprintf(stderr,"Usage:%s portnumber\a\n",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\n\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\n\a",strerror(errno));   
  46.      exit(1);   
  47.   }   
  48.   /* 监听sockfd描述符 */   
  49.   if(listen(sockfd,5)==-1)   
  50.   {   
  51.       fprintf(stderr,"Listen error:%s\n\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\n\a",strerror(errno));   
  61.       exit(1);   
  62.      }   
  63.    fprintf(stderr,"Server get connection from %s\n",   
  64.    inet_ntoa(client_addr.sin_addr));   
  65.    if(write(new_fd,hello,strlen(hello))==-1)   
  66.    {   
  67.       fprintf(stderr,"Write Error:%s\n",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 
  8.         goto out;  
  9.   
  10.     retval = sock_map_fd(sock);//分配一个未使用的文件描述符fd,并将socket和fd建立联系  
  11.     if (retval 
  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的定义如下(include\linux\net.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. };  


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32中断向量表的位置.重定向