首页 > 代码库 > Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)

Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)

本文分析基于Linux Kernel 1.2.13

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

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

作者:闫明

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

 

 

上篇分析了应用层经过BSD socket层到INET socket层的函数调用关系和数据的处理流程,INET层会调用具体的传输层协议,还是以UDP协议为例

udp_write()函数

 

[cpp] view plaincopy
  1. static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,  
  2.       unsigned flags)  
  3. {  
  4.     return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));  
  5. }  

在分析udp_sendto()函数之前,先了解一下sockaddr_in结构,这是标准的网络接口地址结构的定义

 

 

[cpp] view plaincopy
  1. struct sockaddr_in {  
  2.   short int     sin_family; /* Address family   地址族 */  
  3.   unsigned short int    sin_port;   /* Port number  端口号     */  
  4.   struct in_addr    sin_addr;   /* Internet address 网络地址    */  
  5.   
  6.   /* Pad to size of `struct sockaddr‘. */  
  7.   unsigned char     __pad[__SOCK_SIZE__ - sizeof(short int) -  
  8.             sizeof(unsigned short int) - sizeof(struct in_addr)];  
  9. };  
  10. #define sin_zero    __pad       /* for BSD UNIX comp. -FvK  */  

udp_sentdto()函数

 

 

[cpp] view plaincopy
  1. static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,  
  2.        unsigned flags, struct sockaddr_in *usin, int addr_len)  
  3. {  
  4.     struct sockaddr_in sin;  
  5.     int tmp;  
  6.   
  7.     /*  
  8.      *  Check the flags. We support no flags for UDP sending 
  9.      */  
  10.     if (flags&~MSG_DONTROUTE)   
  11.         return(-EINVAL);  
  12.     /* 
  13.      *  Get and verify the address.  
  14.      */  
  15.        
  16.     if (usin) //如果usin不是空  
  17.     {  
  18.         if (addr_len < sizeof(sin))   
  19.             return(-EINVAL);  
  20.         memcpy(&sin,usin,sizeof(sin));  
  21.         if (sin.sin_family && sin.sin_family != AF_INET)  
  22.             return(-EINVAL);  
  23.         if (sin.sin_port == 0)   
  24.             return(-EINVAL);  
  25.     }   
  26.     else //usin为空  
  27.     {  
  28.         if (sk->state != TCP_ESTABLISHED)   
  29.             return(-EINVAL);  
  30.         sin.sin_family = AF_INET;//协议族  
  31.         sin.sin_port = sk->dummy_th.dest;//目的端口  
  32.         sin.sin_addr.s_addr = sk->daddr;//目的地址  
  33.     }  
  34.     
  35.     /* 
  36.      *  BSD socket semantics. You must set SO_BROADCAST to permit 
  37.      *  broadcasting of data. 
  38.      */  
  39.        
  40.     if(sin.sin_addr.s_addr==INADDR_ANY)//目的地址是全0地址,对应当前主机  
  41.         sin.sin_addr.s_addr=ip_my_addr();//将目的地址设为当前主机的网络地址  
  42.           
  43.     if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)  
  44.             return -EACCES;         /* Must turn broadcast on first */  
  45.   
  46.     sk->inuse = 1;  
  47.   
  48.     /* Send the packet. */  
  49.     tmp = udp_send(sk, &sin, from, len, flags);//调用udp_send()真正的发送数据  
  50.   
  51.     /* The datagram has been sent off.  Release the socket. */  
  52.     release_sock(sk);  
  53.     return(tmp);  
  54. }  

udp_send()函数

 

 

[cpp] view plaincopy
  1. static int udp_send(struct sock *sk, //要发送的数据包使用的协议对用的sock结构  
  2.                        struct sockaddr_in *sin,//目的端的标准的网络接口地址  
  3.                        unsigned char *from,//要发送的数据所在地址  
  4.                        int len,//发送数据的长度  
  5.                        int rt)  
  6. {  
  7.     struct sk_buff *skb;  
  8.     struct device *dev;  
  9.     struct udphdr *uh;  
  10.     unsigned char *buff;  
  11.     unsigned long saddr;  
  12.     int size, tmp;  
  13.     int ttl;  
  14.     
  15.     /*  
  16.      *  Allocate an sk_buff copy of the packet. 
  17.      */  
  18.        
  19.     size = sk->prot->max_header + len;//计算大小为UDP最长表头+ 数据长度  
  20.     skb = sock_alloc_send_skb(sk, size, 0, &tmp);//根据要发送的数据分配sk_buff结构空间并对当前套接字状态检查  
  21.   
  22.   
  23.     if (skb == NULL)   
  24.         return tmp;  
  25.   
  26.     skb->sk       = NULL;    /* to avoid changing sk->saddr */  
  27.     skb->free     = 1;  
  28.     skb->localroute = sk->localroute|(rt&MSG_DONTROUTE);  
  29.   
  30.     /* 
  31.      *  Now build the IP and MAC header.  
  32.      */  
  33.        
  34.     buff = skb->data;//将skb中的数据指针赋值给buff指针  
  35.     saddr = sk->saddr;//本地地址  
  36.     dev = NULL;  
  37.     ttl = sk->ip_ttl;//生存时间  
  38. #ifdef CONFIG_IP_MULTICAST  
  39.     if (MULTICAST(sin->sin_addr.s_addr))  
  40.         ttl = sk->ip_mc_ttl;  
  41. #endif  
  42.     tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,  
  43.             &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,ttl);//调用ip_build_header()创建IP报头和调用ip_send()创建MAC首部  
  44.   
  45.     skb->sk=sk;  /* So memory is freed correctly */  
  46.       
  47.     /* 
  48.      *  Unable to put a header on the packet. 
  49.      */  
  50.                   
  51.     if (tmp < 0 )   
  52.     {  
  53.         sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);  
  54.         return(tmp);  
  55.     }  
  56.       
  57.     buff += tmp;  
  58.     saddr = skb->saddr; /*dev->pa_addr;*/  
  59.     skb->len = tmp + sizeof(struct udphdr) + len;    /* len + UDP + IP + MAC */  
  60.     skb->dev = dev;  
  61.       
  62.     /* 
  63.      *  Fill in the UDP header. 填写UDP的报头 
  64.      */  
  65.        
  66.     uh = (struct udphdr *) buff;  
  67.     uh->len = htons(len + sizeof(struct udphdr));//数据包长度  
  68.     uh->source = sk->dummy_th.source;//本地端口  
  69.     uh->dest = sin->sin_port;//远端端口  
  70.     buff = (unsigned char *) (uh + 1);  
  71.   
  72.     /* 
  73.      *  Copy the user data.  
  74.      */  
  75.        
  76.     memcpy_fromfs(buff, from, len);//复制用户数据  
  77.   
  78.     /* 
  79.      *  Set up the UDP checksum.  
  80.      */  
  81.        
  82.     udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);//计算UDP报头的校验和  
  83.   
  84.     /*  
  85.      *  Send the datagram to the interface.  
  86.      */  
  87.        
  88.     udp_statistics.UdpOutDatagrams++;  
  89.        
  90.     sk->prot->queue_xmit(sk, dev, skb, 1);//调用IP层函数发送数据  
  91.     return(len);  
  92. }  

这样要发送的数据填充的sk_buff结构中之后再对UDP数据包添加IP数据报头和MAC帧的首部。最后调用IP层的发送函数发送数据包。

Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)