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

               

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

Kernel version:2.6.14

CPU architecture:ARM920T

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

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

/****************************************************************************//*简介:TCPServer示例 *//****************************************************************************/#include  #include  #include  #include  #include  #include  #include  #include  int main(int argc, char *argv[]) {  int sockfd,new_fd;  struct sockaddr_in server_addr;  struct sockaddr_in client_addr;  int sin_size,portnumber;  const char hello[]="Hello\n"; if(argc!=2)   {      fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);      exit(1);   }   if((portnumber=atoi(argv[1]))<0)   {       fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);       exit(1);  }   /* 服务器端开始建立socket描述符 */   if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)   {      fprintf(stderr,"Socket error:%s\n\a",strerror(errno));      exit(1);   }   /* 服务器端填充 sockaddr结构 */   bzero(&server_addr,sizeof(struct sockaddr_in));   server_addr.sin_family=AF_INET;   server_addr.sin_addr.s_addr=htonl(INADDR_ANY);   server_addr.sin_port=htons(portnumber);   /* 捆绑sockfd描述符 */   if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==   -1)   {      fprintf(stderr,"Bind error:%s\n\a",strerror(errno));      exit(1);   }   /* 监听sockfd描述符 */   if(listen(sockfd,5)==-1)   {       fprintf(stderr,"Listen error:%s\n\a",strerror(errno));       exit(1);   }   while(1)   {   /* 服务器阻塞,直到客户程序建立连接 */    sin_size=sizeof(struct sockaddr_in);    if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)      {       fprintf(stderr,"Accept error:%s\n\a",strerror(errno));       exit(1);      }    fprintf(stderr,"Server get connection from %s\n",    inet_ntoa(client_addr.sin_addr));    if(write(new_fd,hello,strlen(hello))==-1)    {       fprintf(stderr,"Write Error:%s\n",strerror(errno));       exit(1);     }      /* 这个通讯已经结束 */       close(new_fd);   /* 循环下一个 */   }   close(sockfd);   exit(0); }

 下图说明了socketfd是怎样联系起来的。


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

net/socket.c/* * System call vectors.  * * Argument checking cleaned up. Saved 20% in size. *  This function doesn't need to set the kernel lock because *  it is set by the callees.  */asmlinkage long sys_socketcall(int call, unsigned long __user *args){ unsigned long a[6]; unsigned long a0,a1; int err; if(call<1||call>SYS_RECVMSG)  return -EINVAL; /* copy_from_user should be SMP safe. */ if (copy_from_user(a, args, nargs[call]))  return -EFAULT; err = audit_socketcall(nargs[call]/sizeof(unsigned long), a); if (err)  return err; a0=a[0]; a1=a[1];  switch(call)  {  case SYS_SOCKET:   err = sys_socket(a0,a1,a[2]);   break;  case SYS_BIND:   err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]);   break;  case SYS_CONNECT:   err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);   break;  case SYS_LISTEN:   err = sys_listen(a0,a1);   break;  case SYS_ACCEPT:   err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);   break;  case SYS_GETSOCKNAME:   err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);   break;  case SYS_GETPEERNAME:   err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]);   break;  case SYS_SOCKETPAIR:   err = sys_socketpair(a0,a1, a[2], (int __user *)a[3]);   break;  case SYS_SEND:   err = sys_send(a0, (void __user *)a1, a[2], a[3]);   break;  case SYS_SENDTO:   err = sys_sendto(a0,(void __user *)a1, a[2], a[3],      (struct sockaddr __user *)a[4], a[5]);   break;  case SYS_RECV:   err = sys_recv(a0, (void __user *)a1, a[2], a[3]);   break;  case SYS_RECVFROM:   err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],        (struct sockaddr __user *)a[4], (int __user *)a[5]);   break;  case SYS_SHUTDOWN:   err = sys_shutdown(a0,a1);   break;  case SYS_SETSOCKOPT:   err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);   break;  case SYS_GETSOCKOPT:   err = sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]);   break;  case SYS_SENDMSG:   err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]);   break;  case SYS_RECVMSG:   err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]);   break;  default:   err = -EINVAL;   break; } return err;} /* It may be already another descriptor 8) Not kernel problem. */ return retval;out_release: sock_release(sock); return retval;}
 当应用程序使用socket()创建一个socket时,会执行sys_socket,其定义如下

asmlinkage long sys_socket(int family, int type, int protocol){ int retval; struct socket *sock; retval = sock_create(family, type, protocol, &sock);//创建socket if (retval < 0)  goto out; retval = sock_map_fd(sock);//分配一个未使用的文件描述符fd,并将socket和fd建立联系 if (retval < 0)  goto out_release;out: /* It may be already another descriptor 8) Not kernel problem. */ return retval;out_release: sock_release(sock); return retval;}
 结构体socket的定义如下(include\linux\net.h):

struct socket { socket_state  state; unsigned long  flags; struct proto_ops *ops; struct fasync_struct *fasync_list; struct file  *file;//通过这个和文件描述符建立联系 struct sock  *sk; wait_queue_head_t wait; short   type;};
下面我们再来看看sock_map_fd函数

int sock_map_fd(struct socket *sock){ int fd; struct qstr this; char name[32]; /*  * Find a file descriptor suitable for return to the user.   */ fd = get_unused_fd();//分配一个未使用的fd if (fd >= 0) {  struct file *file = get_empty_filp();  if (!file) {   put_unused_fd(fd);   fd = -ENFILE;   goto out;  }  this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);  this.name = 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;//socket操作函数,当使用文件系统的IO函数时,其实使用的是socket的IO函数  file->f_mode = FMODE_READ | FMODE_WRITE;  file->f_flags = O_RDWR;  file->f_pos = 0;  file->private_data = sock;  fd_install(fd, file); }out: return fd;}static struct file_operations socket_file_ops = { .owner = THIS_MODULE, .llseek = no_llseek, .aio_read = sock_aio_read, .aio_write = sock_aio_write, .poll =  sock_poll, .unlocked_ioctl = sock_ioctl, .mmap =  sock_mmap, .open =  sock_no_open, /* special open code to disallow open via /proc */ .release = sock_close, .fasync = sock_fasync, .readv = sock_readv, .writev = sock_writev, .sendpage = sock_sendpage};

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

你可能感兴趣的:(linux内核中的文件描述符 二 --socket和文件描述符)