Linux核心--網路棧實現分析(九)--傳輸層之UDP協議(下)

來源:互聯網
上載者:User

標籤:des   blog   http   ar   os   使用   for   sp   strong   

本文分析基於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協議(下)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.