Linux網(wǎng)絡(luò)編程--7. TCP/IP協(xié)議
發(fā)布時間:2008-09-17 閱讀數(shù): 次 來源:網(wǎng)樂原科技
你也許聽說過TCP/IP協(xié)議,那么你知道到底什么是TCP,什么是IP嗎?在這一章里面,我們一起來學(xué)習(xí)這個目前網(wǎng)絡(luò)上用最廣泛的協(xié)議.
7.1 網(wǎng)絡(luò)傳輸分層
如果你考過計算機(jī)等級考試,那么你就應(yīng)該已經(jīng)知道了網(wǎng)絡(luò)傳輸分層這個概念.在網(wǎng)絡(luò)上,人們?yōu)榱藗鬏敂?shù)據(jù)時的方便,把網(wǎng)絡(luò)的傳輸分為7個層次.分別是:應(yīng)用層,表示層,會話層,傳輸層,網(wǎng)絡(luò)層,數(shù)據(jù)鏈路層和物理層.分好了層以后,傳輸數(shù)據(jù)時,上一層如果要數(shù)據(jù)的話,就可以直接向下一層要了,而不必要管數(shù)據(jù)傳輸?shù)募?xì)節(jié).下一層也只向它的上一層提供數(shù)據(jù),而不要去管其它東西了.如果你不想考試,你沒有必要去記這些東西的.只要知道是分層的,而且各層的作用不同.
7.2 IP協(xié)議
IP協(xié)議是在網(wǎng)絡(luò)層的協(xié)議.它主要完成數(shù)據(jù)包的發(fā)送作用. 下面這個表是IP4的數(shù)據(jù)包格式
0 4 8 16 32
--------------------------------------------------
|版本 |首部長度|服務(wù)類型| 數(shù)據(jù)包總長 |
--------------------------------------------------
| 標(biāo)識 |DF |MF| 碎片偏移 |
--------------------------------------------------
| 生存時間 | 協(xié)議 | 首部較驗和 |
------------------------------------------------
| 源IP地址 |
------------------------------------------------
| 目的IP地址 |
-------------------------------------------------
| 選項 |
=================================================
| 數(shù)據(jù) |
-------------------------------------------------
下面我們看一看IP的結(jié)構(gòu)定義
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協(xié)議的版本號,這里是4,現(xiàn)在IPV6已經(jīng)出來了
ip_hlIP包首部長度,這個值以4字節(jié)為單位.IP協(xié)議首部的固定長度為20個字節(jié),如果IP包沒有選項,那么這個值為5.
ip_tos服務(wù)類型,說明提供的優(yōu)先權(quán).
ip_len說明IP數(shù)據(jù)的長度.以字節(jié)為單位.
ip_id標(biāo)識這個IP數(shù)據(jù)包.
ip_off碎片偏移,這和上面ID一起用來重組碎片的.
ip_ttl生存時間.沒經(jīng)過一個路由的時候減一,直到為0時被拋棄.
ip_p協(xié)議,表示創(chuàng)建這個IP數(shù)據(jù)包的高層協(xié)議.如TCP,UDP協(xié)議.
ip_sum首部校驗和,提供對首部數(shù)據(jù)的校驗.
ip_src,ip_dst發(fā)送者和接收者的IP地址
關(guān)于IP協(xié)議的詳細(xì)情況,請參考 RFC791
7.3 ICMP協(xié)議
ICMP是消息控制協(xié)議,也處于網(wǎng)絡(luò)層.在網(wǎng)絡(luò)上傳遞IP數(shù)據(jù)包時,如果發(fā)生了錯誤,那么就會用ICMP協(xié)議來報告錯誤.
ICMP包的結(jié)構(gòu)如下:
0 8 16 32
---------------------------------------------------------------------
| 類型 | 代碼 | 校驗和 |
--------------------------------------------------------------------
| 數(shù)據(jù) | 數(shù)據(jù) |
--------------------------------------------------------------------
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;
};
關(guān)于ICMP協(xié)議的詳細(xì)情況可以查看 RFC792
7.4 UDP協(xié)議
UDP協(xié)議是建立在IP協(xié)議基礎(chǔ)之上的,用在傳輸層的協(xié)議.UDP和IP協(xié)議一樣是不可靠的數(shù)據(jù)報服務(wù).UDP的頭格式為:
0 16 32
---------------------------------------------------
| UDP源端口 | UDP目的端口 |
---------------------------------------------------
| UDP數(shù)據(jù)報長度 | UDP數(shù)據(jù)報校驗 |
---------------------------------------------------
UDP結(jié)構(gòu)在中的定義為:
struct udphdr {
u_int16_t source;
u_int16_t dest;
u_int16_t len;
u_int16_t check;
};
關(guān)于UDP協(xié)議的詳細(xì)情況,請參考 RFC768
7.5 TCP
TCP協(xié)議也是建立在IP協(xié)議之上的,不過TCP協(xié)議是可靠的.按照順序發(fā)送的.TCP的數(shù)據(jù)結(jié)構(gòu)比前面的結(jié)構(gòu)都要復(fù)雜.
0 4 8 10 16 24 32
-------------------------------------------------------------------
| 源端口 | 目的端口 |
-------------------------------------------------------------------
| 序列號 |
------------------------------------------------------------------
| 確認(rèn)號 |
------------------------------------------------------------------
| | |U|A|P|S|F| |
|首部長度| 保留 |R|C|S|Y|I| 窗口 |
| | |G|K|H|N|N| |
-----------------------------------------------------------------
| 校驗和 | 緊急指針 |
-----------------------------------------------------------------
| 選項 | 填充字節(jié) |
-----------------------------------------------------------------
TCP的結(jié)構(gòu)在中定義為:
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發(fā)送TCP數(shù)據(jù)的源端口
dest接受TCP數(shù)據(jù)的目的端口
seq標(biāo)識該TCP所包含的數(shù)據(jù)字節(jié)的開始序列號
ack_seq確認(rèn)序列號,表示接受方下一次接受的數(shù)據(jù)序列號.
doff數(shù)據(jù)首部長度.和IP協(xié)議一樣,以4字節(jié)為單位.一般的時候為5
urg如果設(shè)置緊急數(shù)據(jù)指針,則該位為1
ack如果確認(rèn)號正確,那么為1
psh如果設(shè)置為1,那么接收方收到數(shù)據(jù)后,立即交給上一層程序
rst為1的時候,表示請求重新連接
syn為1的時候,表示請求建立連接
fin為1的時候,表示親戚關(guān)閉連接
window窗口,告訴接收者可以接收的大小
check對TCP數(shù)據(jù)進(jìn)行較核
urg_ptr如果urg=1,那么指出緊急數(shù)據(jù)對于歷史數(shù)據(jù)開始的序列號的偏移值
關(guān)于TCP協(xié)議的詳細(xì)情況,請查看 RFC793
7.6 TCP連接的建立
TCP協(xié)議是一種可靠的連接,為了保證連接的可靠性,TCP的連接要分為幾個步驟.我們把這個連接過程稱為"三次握手".
下面我們從一個實例來分析建立連接的過程.
第一步客戶機(jī)向服務(wù)器發(fā)送一個TCP數(shù)據(jù)包,表示請求建立連接. 為此,客戶端將數(shù)據(jù)包的SYN位設(shè)置為1,并且設(shè)置序列號seq=1000(我們假設(shè)為1000).
第二步服務(wù)器收到了數(shù)據(jù)包,并從SYN位為1知道這是一個建立請求的連接.于是服務(wù)器也向客戶端發(fā)送一個TCP數(shù)據(jù)包.因為是響應(yīng)客戶機(jī)的請求,于是服務(wù)器設(shè)置ACK為1,sak_seq=1001(1000+1)同時設(shè)置自己的序列號.seq=2000(我們假設(shè)為2000).
第三步客戶機(jī)收到了服務(wù)器的TCP,并從ACK為1和ack_seq=1001知道是從服務(wù)器來的確認(rèn)信息.于是客戶機(jī)也向服務(wù)器發(fā)送確認(rèn)信息.客戶機(jī)設(shè)置ACK=1,和ack_seq=2001,seq=1001,發(fā)送給服務(wù)器.至此客戶端完成連接.
最后一步服務(wù)器受到確認(rèn)信息,也完成連接.
通過上面幾個步驟,一個TCP連接就建立了.當(dāng)然在建立過程中可能出現(xiàn)錯誤,不過TCP協(xié)議可以保證自己去處理錯誤的.
說一說其中的一種錯誤.
聽說過DOS嗎?(可不是操作系統(tǒng)啊).今年春節(jié)的時候,美國的五大網(wǎng)站一起受到攻擊.攻擊者用的就是DOS(拒絕式服務(wù))方式.概括的說一下原理.
客戶機(jī)先進(jìn)行第一個步驟.服務(wù)器收到后,進(jìn)行第二個步驟.按照正常的TCP連接,客戶機(jī)應(yīng)該進(jìn)行第三個步驟.
不過攻擊者實際上并不進(jìn)行第三個步驟.因為客戶端在進(jìn)行第一個步驟的時候,修改了自己的IP地址,就是說將一個實際上不存在的IP填充在自己IP數(shù)據(jù)包的發(fā)送者的IP一欄.這樣因為服務(wù)器發(fā)的IP地址沒有人接收,所以服務(wù)端會收不到第三個步驟的確認(rèn)信號,這樣服務(wù)務(wù)端會在那邊一直等待,直到超時.
這樣當(dāng)有大量的客戶發(fā)出請求后,服務(wù)端會有大量等待,直到所有的資源被用光,而不能再接收客戶機(jī)的請求.
這樣當(dāng)正常的用戶向服務(wù)器發(fā)出請求時,由于沒有了資源而不能成功.于是就出現(xiàn)了春節(jié)時所出現(xiàn)的情況.