diecui1202 发表于 2013-2-7 05:41:19

Linux内核网络协议栈5-socket地址绑定

 
<div style="background-color: transparent; margin: 0px;">一、socket绑定入口
<div style="background-color: transparent; margin: 0px;">1、示例代码
struct sockaddr_in server_address;server_address.sin_family = AF_INET;server_address.sin_addr.s_addr = inet_addr("0.0.0.0");server_address.sin_port = htons(9734);server_len = sizeof(server_address);bind(server_sockfd, (struct sockaddr *)&server_address, server_len); 

2、绑定入口
前面介绍了socket从库函数到内核的过程,其最终都是通过102号中断进入内核,所不同的是子中断号不同;对于绑定,其子中断号是2;

和创建socket一样,绑定socket的处理函数都是:
asmlinkage long sys_socketcall(int call, unsigned long __user *args){   unsigned long a;   unsigned long a0, a1;   int err;   if (copy_from_user(a, args, nargs))          return -EFAULT;   a0 = a;   a1 = a;   switch (call) {          …...   case SYS_BIND:          err = sys_bind(a0, (struct sockaddr __user *)a1, a);          …...} 
根据子中断号,内核会执行sys_bind()函数来完成地址的绑定;

二、绑定的具体过程
sys_bind()函数如下,一起来分析一下它的主要过程:
asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen){   struct socket *sock;   char address;   int err, fput_needed;    // 1, 根据fd查找相应的socket结构   sock = sockfd_lookup_light(fd, &err, &fput_needed);   if (sock) {            // 2, 将用户空间的地址结构拷贝到内核空间          err = move_addr_to_kernel(umyaddr, addrlen, address);          if (err >= 0) {               err = security_socket_bind(sock,                                        (struct sockaddr *)address,                                        addrlen);               if (!err)                        // 3, 根据协议域及socket类型,调用相应的bind函数                        err = sock->ops->bind(sock,                                           (struct sockaddr *)                                           address, addrlen);          }          fput_light(sock->file, fput_needed);   }   return err;}
上面的过程中:
1、根据fd找到相应的socket结构
在创建socket的最后,会将socket结构与文件系统关联,并返回给应用程序与socket相关的文件描述符;这里是根据应用程序传递过来的文件描述符取得关联的socket结构;
下面看看从fd取得socket结构的代码:
static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed){   struct file *file;   struct socket *sock;   *err = -EBADF;   file = fget_light(fd, fput_needed);   if (file) {          sock = sock_from_file(file, err);          if (sock)               return sock;          fput_light(file, *fput_needed);   }   return NULL;}
再到fget_lignt()去看看:
struct file *fget_light(unsigned int fd, int *fput_needed){   struct file *file;   struct files_struct *files = current->files;   …...   file = fcheck_files(files, fd);   …...   return file;}
这里current宏返回当前运行的进程的描述符,current->files返回当前进程的打开文件表;函数fcheck_files(files, fd)根据fd从打开文件表里取出相应的file结构变量;
在创建socket中提到,file与socket关联,是通过file->private=socket完成的,因为获取到file结构变量后,也可以通过同样的方式取得socket结构变量;sock_from_file()函数就是用来完成此工作的;
页: [1]
查看完整版本: Linux内核网络协议栈5-socket地址绑定