首页 > 代码库 > Linux内核--网络栈实现分析(八)--应用层发送数据(下)

Linux内核--网络栈实现分析(八)--应用层发送数据(下)

本文分析基于Linux Kernel 1.2.13

原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7547826

更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html

作者:闫明

注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。

 

下面是发送数据的流程:

应用层发送数据包的入口函数是BSD socket层的sock_write()函数,在分析该函数之前,先分析下socket的创建,系统调用sys_socket()对应的BSD socket层函数为sock_socket()

sock_socket()函数

 

[cpp] view plaincopy
  1. /* 
  2.  *  Perform the socket system call. we locate the appropriate 
  3.  *  family, then create a fresh socket. 
  4.  */  
  5.   
  6. static int sock_socket(int family, int type, int protocol)  
  7. {  
  8.     int i, fd;  
  9.     struct socket *sock;  
  10.     struct proto_ops *ops;  
  11.   
  12.     /* Locate the correct protocol family. */  
  13.     for (i = 0; i < NPROTO; ++i) //查找对应的协议族  
  14.     {  
  15.         if (pops[i] == NULL) continue;  
  16.         if (pops[i]->family == family)   
  17.             break;  
  18.     }  
  19.   
  20.     if (i == NPROTO) //查找未果,返回错误  
  21.     {  
  22.         return -EINVAL;  
  23.     }  
  24.   
  25.     ops = pops[i];//指针指向该协议族的原型操作函数集  
  26.   
  27. /* 
  28.  *  Check that this is a type that we know how to manipulate and 
  29.  *  the protocol makes sense here. The family can still reject the 
  30.  *  protocol later. 
  31.  */  
  32.     
  33.     if ((type != SOCK_STREAM && type != SOCK_DGRAM &&  
  34.         type != SOCK_SEQPACKET && type != SOCK_RAW &&  
  35.         type != SOCK_PACKET) || protocol < 0)  
  36.             return(-EINVAL);  
  37.   
  38. /* 
  39.  *  Allocate the socket and allow the family to set things up. if 
  40.  *  the protocol is 0, the family is instructed to select an appropriate 
  41.  *  default. 
  42.  */  
  43.   
  44.     if (!(sock = sock_alloc())) //获取一个socket,已经完成了socket部分初始化设置  
  45.     {  
  46.         printk("NET: sock_socket: no more sockets\n");  
  47.         return(-ENOSR); /* Was: EAGAIN, but we are out of 
  48.                    system resources! */  
  49.     }  
  50.   
  51.     sock->type = type;  
  52.     sock->ops = ops;  
  53.     if ((i = sock->ops->create(sock, protocol)) < 0) //调用INET层函数,inet_create()函数,创建inet层的socket,即sock结构  
  54.     {  
  55.         sock_release(sock);  
  56.         return(i);  
  57.     }  
  58.   
  59.     if ((fd = get_fd(SOCK_INODE(sock))) < 0) //根据sock结构中的inode,分配文件描述符  
  60.     {  
  61.         sock_release(sock);  
  62.         return(-EINVAL);  
  63.     }  
  64.   
  65.     return(fd);  
  66. }  

该函数的大体功能:

 

1、分配socket,sock结构,用于BSD和INET层的socket

2、分配inode和file结构,用于文件操作

3、返回文件操作描述符,用于应用程序的使用

其中初始化分配一个socket的方法如下:

 

[cpp] view plaincopy
  1. /* 
  2.  *  Allocate a socket. 
  3.  */  
  4.   
  5. struct socket *sock_alloc(void)  
  6. {  
  7.     struct inode * inode;  
  8.     struct socket * sock;  
  9.   
  10.     inode = get_empty_inode();//获一个空的文件结点  
  11.     if (!inode)  
  12.         return NULL;  
  13.     //文件结点相应字段赋值  
  14.     inode->i_mode = S_IFSOCK;  
  15.     inode->i_sock = 1;  
  16.     inode->i_uid = current->uid;  
  17.     inode->i_gid = current->gid;  
  18.   
  19.     sock = &inode->u.socket_i;//给sicket结构指针赋值,可以看到inode和socket一一对应  
  20.     sock->state = SS_UNCONNECTED;  
  21.     sock->flags = 0;  
  22.     sock->ops = NULL;  
  23.     sock->data = NULL;  
  24.     sock->conn = NULL;  
  25.     sock->iconn = NULL;  
  26.     sock->next = NULL;  
  27.     sock->wait = &inode->i_wait;  
  28.     sock->inode = inode;     /* "backlink": we could use pointer arithmetic instead */  
  29.     sock->fasync_list = NULL;  
  30.     sockets_in_use++;  
  31.     return sock;  
  32. }  

执行完,然后调用INET层的inet_create()函数

 

 

[cpp] view plaincopy
  1. /* 
  2.  *  Create an inet socket. 
  3.  * 
  4.  *  FIXME: Gcc would generate much better code if we set the parameters 
  5.  *  up in in-memory structure order. Gcc68K even more so 
  6.  */  
  7. //创建inet socket,即sock结构  
  8. static int inet_create(struct socket *sock, int protocol)  
  9. {  
  10.     struct sock *sk;  
  11.     struct proto *prot;  
  12.     int err;  
  13.   
  14.     sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);//分配空间  
  15.     if (sk == NULL)   
  16.         return(-ENOBUFS);  
  17.     sk->num = 0;  
  18.     sk->reuse = 0;  
  19.     switch(sock->type)   
  20.     {  
  21.         case SOCK_STREAM:  
  22.         case SOCK_SEQPACKET:  
  23.             .................  
  24.   
  25.         case SOCK_DGRAM:  
  26.             if (protocol && protocol != IPPROTO_UDP)   
  27.             {  
  28.                 kfree_s((void *)sk, sizeof(*sk));  
  29.                 return(-EPROTONOSUPPORT);  
  30.             }  
  31.             protocol = IPPROTO_UDP;  
  32.             sk->no_check = UDP_NO_CHECK;  
  33.             prot=&udp_prot;//原型指针指向UDP的原型定义  
  34.             break;  
  35.         
  36.         case SOCK_RAW:  
  37.             .........................  
  38.             break;  
  39.   
  40.         case SOCK_PACKET:  
  41.             ..........................  
  42.             break;  
  43.   
  44.         default:  
  45.             kfree_s((void *)sk, sizeof(*sk));  
  46.             return(-ESOCKTNOSUPPORT);  
  47.     }  
  48.     sk->socket = sock;//可以看出sock和socket的对应关系  
  49. .................  
  50.     sk->type = sock->type;  
  51.     sk->stamp.tv_sec=0;  
  52.     sk->protocol = protocol;  
  53.     sk->wmem_alloc = 0;  
  54.     sk->rmem_alloc = 0;  
  55.     sk->sndbuf = SK_WMEM_MAX;  
  56.     sk->rcvbuf = SK_RMEM_MAX;  
  57.     ......................................//sock的初始化  
  58.   
  59.     /* this is how many unacked bytes we will accept for this socket.  */  
  60.     sk->max_unacked = 2048; /* needs to be at most 2 full packets. */  
  61.   
  62.     /* how many packets we should send before forcing an ack.  
  63.        if this is set to zero it is the same as sk->delay_acks = 0 */  
  64.     sk->max_ack_backlog = 0;  
  65.     sk->inuse = 0;  
  66.     sk->delay_acks = 0;  
  67.     skb_queue_head_init(&sk->write_queue);  
  68.     skb_queue_head_init(&sk->receive_queue);  
  69.     sk->mtu = 576;  
  70.     sk->prot = prot;  
  71.     sk->sleep = sock->wait;  
  72.     sk->daddr = 0;//远端地址  
  73.     sk->saddr = 0 /* ip_my_addr() */;//本地地址  
  74.     sk->err = 0;  
  75.     sk->next = NULL;  
  76.     sk->pair = NULL;  
  77.     sk->send_tail = NULL;//发送链表尾  
  78.     sk->send_head = NULL;//发送链表头  
  79.     ..............................  
  80.     skb_queue_head_init(&sk->back_log);//初始化双链表  
  81.     ..................................  
  82.     sk->ip_tos=0;  
  83.     sk->ip_ttl=64;  
  84. ...................................  
  85.       
  86.   
  87.     if (sk->num) //本地端口号不空  
  88.     {  
  89.     /* 
  90.      * It assumes that any protocol which allows 
  91.      * the user to assign a number at socket 
  92.      * creation time automatically 
  93.      * shares. 
  94.      */  
  95.         put_sock(sk->num, sk);//根据端口号将sock结构加入sock表中  
  96.         sk->dummy_th.source = ntohs(sk->num);  
  97.     }  
  98.   
  99.     if (sk->prot->init) //UDP的初始化函数为空  
  100.     {  
  101.         err = sk->prot->init(sk);  
  102.         if (err != 0)   
  103.         {  
  104.             destroy_sock(sk);  
  105.             return(err);  
  106.         }  
  107.     }  
  108.     return(0);  
  109. }  

返回文件描述的操作符

 

 

[cpp] view plaincopy
  1. /* 
  2.  *  Obtains the first available file descriptor and sets it up for use.  
  3.  */  
  4. //根据文件inode指针创建文件结构,并返回文件操作的操作符,用于应用程序的使用  
  5. static int get_fd(struct inode *inode)  
  6. {  
  7.     int fd;  
  8.     struct file *file;  
  9.   
  10.     /* 
  11.      *  Find a file descriptor suitable for return to the user.  
  12.      */  
  13.   
  14.     file = get_empty_filp();  
  15.     if (!file)   
  16.         return(-1);  
  17.   
  18.     for (fd = 0; fd < NR_OPEN; ++fd)  
  19.         if (!current->files->fd[fd])   
  20.             break;  
  21.     if (fd == NR_OPEN)   
  22.     {  
  23.         file->f_count = 0;  
  24.         return(-1);  
  25.     }  
  26.   
  27.     FD_CLR(fd, &current->files->close_on_exec);  
  28.         current->files->fd[fd] = file;  
  29.     file->f_op = &socket_file_ops;  
  30.     file->f_mode = 3;  
  31.     file->f_flags = O_RDWR;  
  32.     file->f_count = 1;  
  33.     file->f_inode = inode;  
  34.     if (inode)   
  35.         inode->i_count++;  
  36.     file->f_pos = 0;  
  37.     return(fd);  
  38. }  

下面开始正式看发送数据的最顶层函数--sock_write()函数

 

 

[cpp] view plaincopy
  1. /* 
  2.  *  Write data to a socket. We verify that the user area ubuf..ubuf+size-1 is 
  3.  *  readable by the user process. 
  4.  */  
  5.   
  6. static int sock_write(struct inode *inode, struct file *file, char *ubuf, int size)  
  7. {  
  8.     struct socket *sock;  
  9.     int err;  
  10.       
  11.     if (!(sock = socki_lookup(inode))) //返回inode结构的对应的socket结构  
  12.     {  
  13.         printk("NET: sock_write: can‘t find socket for inode!\n");  
  14.         return(-EBADF);  
  15.     }  
  16.   
  17.     if (sock->flags & SO_ACCEPTCON)   
  18.         return(-EINVAL);  
  19.       
  20.     if(size<0)  
  21.         return -EINVAL;  
  22.     if(size==0)  
  23.         return 0;  
  24.           
  25.     if ((err=verify_area(VERIFY_READ,ubuf,size))<0)  
  26.         return err;  
  27.     return(sock->ops->write(sock, ubuf, size,(file->f_flags & O_NONBLOCK)));//调用inet_write()函数  
  28. }  

inet_write()函数

 

 

[cpp] view plaincopy
  1. static int inet_write(struct socket *sock, char *ubuf, int size, int noblock)  
  2. {  
  3.     return inet_send(sock,ubuf,size,noblock,0);  
  4. }  

inet_send()函数

 

 

[cpp] view plaincopy
  1. static int inet_send(struct socket *sock, void *ubuf, int size, int noblock,   
  2.            unsigned flags)  
  3. {  
  4.     struct sock *sk = (struct sock *) sock->data;//从socket结构中取出sock指针  
  5.     if (sk->shutdown & SEND_SHUTDOWN)   
  6.     {  
  7.         send_sig(SIGPIPE, current, 1);  
  8.         return(-EPIPE);  
  9.     }  
  10.     if(sk->err)  
  11.         return inet_error(sk);  
  12.     /* We may need to bind the socket. */  
  13.     if(inet_autobind(sk)!=0)//自动分配本地端口号,并将sk根据端口号加入sock表中  
  14.         return(-EAGAIN);  
  15.     return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags));//调用udp_write()函数  
  16. }  

 

 

这样系统就会调用传输层(还是以UDP为例)的函数udp_write()来发送数据,这样数据就从应用层到了传输层。下篇分析传输层向网络层的数据传输。

Linux内核--网络栈实现分析(八)--应用层发送数据(下)