發新話題

[分享] Linux網絡編程--7. TCP/IP協議

Linux網絡編程--7. TCP/IP協議

    你也許聽說過TCP/IP協議,那麼你知道到底什麼是TCP,什麼是IP嗎?在這一章裡面,我們一起來學習這個目前網絡上用最廣泛的協議.  


7.1 網絡傳輸分層  
如果你考過計算機等級考試,那麼你就應該已經知道了網絡傳輸分層這個概念.在網絡上,人們為了傳輸數據時的方便,把網絡的傳輸分為7個層次.分別是:應用層,表示層,會話層,傳輸層,網絡層,數據鏈路層和物理層.分好了層以後,傳輸數據時,上一層如果要數據的話,就可以直接向下一層要了,而不必要管數據傳輸的細節.下一層也只向它的上一層提供數據,而不要去管其它東西了.如果你不想考試,你沒有必要去記這些東西的.只要知道是分層的,而且各層的作用不同.  

7.2 IP協議  
IP協議是在網絡層的協議.它主要完成數據包的發送作用. 下面這個表是IP4的數據包格式  

0      4       8       16                      32
--------------------------------------------------
|版本   |首部長度|服務類型|    數據包總長       |
--------------------------------------------------
|    標識                 |DF |MF| 碎片偏移      |
--------------------------------------------------
|   生存時間    |  協議   |  首部較驗和         |
------------------------------------------------
|               源IP地址                        |
------------------------------------------------
|               目的IP地址                      |
-------------------------------------------------
|               選項                            |
=================================================
|               數據                            |
-------------------------------------------------                        

下面我們看一看IP的結構定義  

struct ip
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int ip_hl:4;           /* header length */
        unsigned int ip_v:4;            /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
        unsigned int ip_v:4;            /* version */
        unsigned int ip_hl:4;           /* header length */
#endif
        u_int8_t ip_tos;                /* type of service */
        u_short ip_len;                 /* total length */
        u_short ip_id;                  /* identification */
        u_short ip_off;                 /* fragment offset field */
#define IP_RF 0x8000                    /* reserved fragment flag */
#define IP_DF 0x4000                    /* dont fragment flag */
#define IP_MF 0x2000                    /* more fragments flag */
#define IP_OFFMASK 0x1fff               /* mask for fragmenting bits */
        u_int8_t ip_ttl;                /* time to live */
        u_int8_t ip_p;                  /* protocol */
        u_short ip_sum;                 /* checksum */
        struct in_addr ip_src, ip_dst;  /* source and dest address */
  };

ip_vIP協議的版本號,這裡是4,現在IPV6已經出來了  

ip_hlIP包首部長度,這個值以4字節為單位.IP協議首部的固定長度為20個字節,如果IP包沒有選項,那麼這個值為5.  

ip_tos服務類型,說明提供的優先權.  

ip_len說明IP數據的長度.以字節為單位.  

ip_id標識這個IP數據包.  

ip_off碎片偏移,這和上面ID一起用來重組碎片的.  

ip_ttl生存時間.沒經過一個路由的時候減一,直到為0時被拋棄.  

ip_p協議,表示創建這個IP數據包的高層協議.如TCP,UDP協議.  

ip_sum首部校驗和,提供對首部數據的校驗.  

ip_src,ip_dst發送者和接收者的IP地址  

關於IP協議的詳細情況,請參考 RFC791

7.3 ICMP協議  
ICMP是消息控制協議,也處於網絡層.在網絡上傳遞IP數據包時,如果發生了錯誤,那麼就會用ICMP協議來報告錯誤.  

ICMP包的結構如下:  

0              8               16                              32
---------------------------------------------------------------------
|       類型    |       代碼    |       校驗和                  |
--------------------------------------------------------------------
|               數據            |       數據                    |
--------------------------------------------------------------------

ICMP在中的定義是  
struct icmphdr
{
  u_int8_t type;                /* message type */
  u_int8_t code;                /* type sub-code */
  u_int16_t checksum;
  union
  {
    struct
    {
      u_int16_t id;
      u_int16_t sequence;
    } echo;                     /* echo datagram */
    u_int32_t   gateway;        /* gateway address */
    struct
    {
      u_int16_t __unused;
      u_int16_t mtu;
    } frag;                     /* path mtu discovery */
  } un;
};

關於ICMP協議的詳細情況可以查看 RFC792

7.4 UDP協議  
UDP協議是建立在IP協議基礎之上的,用在傳輸層的協議.UDP和IP協議一樣是不可靠的數據報服務.UDP的頭格式為:  


0                      16                      32
---------------------------------------------------
|       UDP源端口       |       UDP目的端口     |
---------------------------------------------------
|       UDP數據報長度   |       UDP數據報校驗   |
---------------------------------------------------

UDP結構在中的定義為:  
struct udphdr {
  u_int16_t     source;
  u_int16_t     dest;
  u_int16_t     len;
  u_int16_t     check;
};

關於UDP協議的詳細情況,請參考 RFC768
7.5 TCP  
TCP協議也是建立在IP協議之上的,不過TCP協議是可靠的.按照順序發送的.TCP的數據結構比前面的結構都要複雜.  

0       4       8  10           16              24              32
-------------------------------------------------------------------
|               源端口          |               目的端口        |
-------------------------------------------------------------------
|                               序列號                          |
------------------------------------------------------------------
|                               確認號                          |
------------------------------------------------------------------
|        |            |U|A|P|S|F|                               |
|首部長度| 保留       |R|C|S|Y|I|       窗口                    |
|        |            |G|K|H|N|N|                               |
-----------------------------------------------------------------
|               校驗和          |               緊急指針        |
-----------------------------------------------------------------
|                       選項                    |    填充字節   |
-----------------------------------------------------------------

TCP的結構在中定義為:  
struct tcphdr
  {
    u_int16_t source;
    u_int16_t dest;
    u_int32_t seq;
    u_int32_t ack_seq;
#if __BYTE_ORDER == __LITTLE_ENDIAN
    u_int16_t res1:4;
    u_int16_t doff:4;
    u_int16_t fin:1;
    u_int16_t syn:1;
    u_int16_t rst:1;
    u_int16_t psh:1;
    u_int16_t ack:1;
    u_int16_t urg:1;
    u_int16_t res2:2;
#elif __BYTE_ORDER == __BIG_ENDIAN
    u_int16_t doff:4;
    u_int16_t res1:4;
    u_int16_t res2:2;
    u_int16_t urg:1;
    u_int16_t ack:1;
    u_int16_t psh:1;
    u_int16_t rst:1;
    u_int16_t syn:1;
    u_int16_t fin:1;
#endif
    u_int16_t window;
    u_int16_t check;
    u_int16_t urg_prt;
};      

source發送TCP數據的源端口  
dest接受TCP數據的目的端口  

seq標識該TCP所包含的數據字節的開始序列號  

ack_seq確認序列號,表示接受方下一次接受的數據序列號.  

doff數據首部長度.和IP協議一樣,以4字節為單位.一般的時候為5  

urg如果設置緊急數據指針,則該位為1  

ack如果確認號正確,那麼為1  

psh如果設置為1,那麼接收方收到數據後,立即交給上一層程序  

rst為1的時候,表示請求重新連接  

syn為1的時候,表示請求建立連接  

fin為1的時候,表示親戚關閉連接  

window窗口,告訴接收者可以接收的大小  

check對TCP數據進行較核  

urg_ptr如果urg=1,那麼指出緊急數據對於歷史數據開始的序列號的偏移值  

關於TCP協議的詳細情況,請查看 RFC793

TOP

7.6 TCP連接的建立  
TCP協議是一種可靠的連接,為了保證連接的可靠性,TCP的連接要分為幾個步驟.我們把這個連接過程稱為"三次握手".  

下面我們從一個實例來分析建立連接的過程.  

第一步客戶機向服務器發送一個TCP數據包,表示請求建立連接. 為此,客戶端將數據包的SYN位設置為1,並且設置序列號seq=1000(我們假設為1000).  

第二步服務器收到了數據包,並從SYN位為1知道這是一個建立請求的連接.於是服務器也向客戶端發送一個TCP數據包.因為是響應客戶機的請求,於是服務器設置ACK為1,sak_seq=1001(1000+1)同時設置自己的序列號.seq=2000(我們假設為2000).  

第三步客戶機收到了服務器的TCP,並從ACK為1和ack_seq=1001知道是從服務器來的確認信息.於是客戶機也向服務器發送確認信息.客戶機設置ACK=1,和ack_seq=2001,seq=1001,發送給服務器.至此客戶端完成連接.  

最後一步服務器受到確認信息,也完成連接.  

通過上面幾個步驟,一個TCP連接就建立了.當然在建立過程中可能出現錯誤,不過TCP協議可以保證自己去處理錯誤的.  


  說一說其中的一種錯誤.
  聽說過DOS嗎?(可不是操作系統啊).今年春節的時候,美國的五大網站一起受到攻擊.攻擊者用的就是DOS(拒絕式服務)方式.概括的說一下原理.
  客戶機先進行第一個步驟.服務器收到後,進行第二個步驟.按照正常的TCP連接,客戶機應該進行第三個步驟.
不過攻擊者實際上並不進行第三個步驟.因為客戶端在進行第一個步驟的時候,修改了自己的IP地址,就是說將一個實際上不存在的IP填充在自己IP數據包的發送者的IP一欄.這樣因為服務器發的IP地址沒有人接收,所以服務端會收不到第三個步驟的確認信號,這樣服務務端會在那邊一直等待,直到超時.
這樣當有大量的客戶發出請求後,服務端會有大量等待,直到所有的資源被用光,而不能再接收客戶機的請求.
這樣當正常的用戶向服務器發出請求時,由於沒有了資源而不能成功.於是就出現了春節時所出現的情況.

TOP

發新話題

本站所有圖文均屬網友發表,僅代表作者的觀點與本站無關,如有侵權請通知版主會盡快刪除。