?? linux網絡編程--7. tcpip協議.html
字號:
</tr><td align=center><table border="0" width="80%" cellspacing="0" cellpadding="0" align=center><tr><td valign=top><font color=#cccccc>
<br> 你也許聽說過TCP/IP協議,那么你知道到底什么是TCP,什么是IP嗎?在這一章里面,我們一起來學習這個目前網絡上用最廣泛的協議.
<br>
<br>
<br>7.1 網絡傳輸分層
<br>如果你考過計算機等級考試,那么你就應該已經知道了網絡傳輸分層這個概念.在網絡上,人們為了傳輸數據時的方便,把網絡的傳輸分為7個層次.分別是:應用層,表示層,會話層,傳輸層,網絡層,數據鏈路層和物理層.分好了層以后,傳輸數據時,上一層如果要數據的話,就可以直接向下一層要了,而不必要管數據傳輸的細節.下一層也只向它的上一層提供數據,而不要去管其它東西了.如果你不想考試,你沒有必要去記這些東西的.只要知道是分層的,而且各層的作用不同.
<br>
<br>7.2 IP協議
<br>IP協議是在網絡層的協議.它主要完成數據包的發送作用. 下面這個表是IP4的數據包格式
<br>
<br> 0 4 8 16 32
<br>--------------------------------------------------
<br>|版本 |首部長度|服務類型| 數據包總長 |
<br>--------------------------------------------------
<br>| 標識 |DF |MF| 碎片偏移 |
<br>--------------------------------------------------
<br>| 生存時間 | 協議 | 首部較驗和 |
<br>------------------------------------------------
<br>| 源IP地址 |
<br>------------------------------------------------
<br>| 目的IP地址 |
<br>-------------------------------------------------
<br>| 選項 |
<br>=================================================
<br>| 數據 |
<br>-------------------------------------------------
<br>
<br>下面我們看一看IP的結構定義<netinet/ip.h>
<br>
<br>struct ip
<br> {
<br>#if __BYTE_ORDER == __LITTLE_ENDIAN
<br> unsigned int ip_hl:4; /* header length */
<br> unsigned int ip_v:4; /* version */
<br>#endif
<br>#if __BYTE_ORDER == __BIG_ENDIAN
<br> unsigned int ip_v:4; /* version */
<br> unsigned int ip_hl:4; /* header length */
<br>#endif
<br> u_int8_t ip_tos; /* type of service */
<br> u_short ip_len; /* total length */
<br> u_short ip_id; /* identification */
<br> u_short ip_off; /* fragment offset field */
<br>#define IP_RF 0x8000 /* reserved fragment flag */
<br>#define IP_DF 0x4000 /* dont fragment flag */
<br>#define IP_MF 0x2000 /* more fragments flag */
<br>#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
<br> u_int8_t ip_ttl; /* time to live */
<br> u_int8_t ip_p; /* protocol */
<br> u_short ip_sum; /* checksum */
<br> struct in_addr ip_src, ip_dst; /* source and dest address */
<br> };
<br>
<br>ip_vIP協議的版本號,這里是4,現在IPV6已經出來了
<br>
<br>ip_hlIP包首部長度,這個值以4字節為單位.IP協議首部的固定長度為20個字節,如果IP包沒有選項,那么這個值為5.
<br>
<br>ip_tos服務類型,說明提供的優先權.
<br>
<br>ip_len說明IP數據的長度.以字節為單位.
<br>
<br>ip_id標識這個IP數據包.
<br>
<br>ip_off碎片偏移,這和上面ID一起用來重組碎片的.
<br>
<br>ip_ttl生存時間.沒經過一個路由的時候減一,直到為0時被拋棄.
<br>
<br>ip_p協議,表示創建這個IP數據包的高層協議.如TCP,UDP協議.
<br>
<br>ip_sum首部校驗和,提供對首部數據的校驗.
<br>
<br>ip_src,ip_dst發送者和接收者的IP地址
<br>
<br>關于IP協議的詳細情況,請參考 RFC791
<br>
<br>7.3 ICMP協議
<br>ICMP是消息控制協議,也處于網絡層.在網絡上傳遞IP數據包時,如果發生了錯誤,那么就會用ICMP協議來報告錯誤.
<br>
<br>ICMP包的結構如下:
<br>
<br> 0 8 16 32
<br>---------------------------------------------------------------------
<br>| 類型 | 代碼 | 校驗和 |
<br>--------------------------------------------------------------------
<br>| 數據 | 數據 |
<br>--------------------------------------------------------------------
<br>
<br>ICMP在<netinet/ip_icmp.h>中的定義是
<br>struct icmphdr
<br>{
<br> u_int8_t type; /* message type */
<br> u_int8_t code; /* type sub-code */
<br> u_int16_t checksum;
<br> union
<br> {
<br> struct
<br> {
<br> u_int16_t id;
<br> u_int16_t sequence;
<br> } echo; /* echo datagram */
<br> u_int32_t gateway; /* gateway address */
<br> struct
<br> {
<br> u_int16_t __unused;
<br> u_int16_t mtu;
<br> } frag; /* path mtu discovery */
<br> } un;
<br>};
<br>
<br>關于ICMP協議的詳細情況可以查看 RFC792
<br>
<br>7.4 UDP協議
<br>UDP協議是建立在IP協議基礎之上的,用在傳輸層的協議.UDP和IP協議一樣是不可靠的數據報服務.UDP的頭格式為:
<br>
<br>
<br> 0 16 32
<br>---------------------------------------------------
<br>| UDP源端口 | UDP目的端口 |
<br>---------------------------------------------------
<br>| UDP數據報長度 | UDP數據報校驗 |
<br>---------------------------------------------------
<br>
<br>UDP結構在<netinet/udp.h>中的定義為:
<br>struct udphdr {
<br> u_int16_t source;
<br> u_int16_t dest;
<br> u_int16_t len;
<br> u_int16_t check;
<br>};
<br>
<br>關于UDP協議的詳細情況,請參考 RFC768
<br>7.5 TCP
<br>TCP協議也是建立在IP協議之上的,不過TCP協議是可靠的.按照順序發送的.TCP的數據結構比前面的結構都要復雜.
<br>
<br>0 4 8 10 16 24 32
<br>-------------------------------------------------------------------
<br>| 源端口 | 目的端口 |
<br>-------------------------------------------------------------------
<br>| 序列號 |
<br>------------------------------------------------------------------
<br>| 確認號 |
<br>------------------------------------------------------------------
<br>| | |U|A|P|S|F| |
<br>|首部長度| 保留 |R|C|S|Y|I| 窗口 |
<br>| | |G|K|H|N|N| |
<br>-----------------------------------------------------------------
<br>| 校驗和 | 緊急指針 |
<br>-----------------------------------------------------------------
<br>| 選項 | 填充字節 |
<br>-----------------------------------------------------------------
<br>
<br>TCP的結構在<netinet/tcp.h>中定義為:
<br>struct tcphdr
<br> {
<br> u_int16_t source;
<br> u_int16_t dest;
<br> u_int32_t seq;
<br> u_int32_t ack_seq;
<br>#if __BYTE_ORDER == __LITTLE_ENDIAN
<br> u_int16_t res1:4;
<br> u_int16_t doff:4;
<br> u_int16_t fin:1;
<br> u_int16_t syn:1;
<br> u_int16_t rst:1;
<br> u_int16_t psh:1;
<br> u_int16_t ack:1;
<br> u_int16_t urg:1;
<br> u_int16_t res2:2;
<br>#elif __BYTE_ORDER == __BIG_ENDIAN
<br> u_int16_t doff:4;
<br> u_int16_t res1:4;
<br> u_int16_t res2:2;
<br> u_int16_t urg:1;
<br> u_int16_t ack:1;
<br> u_int16_t psh:1;
<br> u_int16_t rst:1;
<br> u_int16_t syn:1;
<br> u_int16_t fin:1;
<br>#endif
<br> u_int16_t window;
<br> u_int16_t check;
<br> u_int16_t urg_prt;
<br>};
<br>
<br>source發送TCP數據的源端口
<br>dest接受TCP數據的目的端口
<br>
<br>seq標識該TCP所包含的數據字節的開始序列號
<br>
<br>ack_seq確認序列號,表示接受方下一次接受的數據序列號.
<br>
<br>doff數據首部長度.和IP協議一樣,以4字節為單位.一般的時候為5
<br>
<br>urg如果設置緊急數據指針,則該位為1
<br>
<br>ack如果確認號正確,那么為1
<br>
<br>psh如果設置為1,那么接收方收到數據后,立即交給上一層程序
<br>
<br>rst為1的時候,表示請求重新連接
<br>
<br>syn為1的時候,表示請求建立連接
<br>
<br>fin為1的時候,表示親戚關閉連接
<br>
<br>window窗口,告訴接收者可以接收的大小
<br>
<br>check對TCP數據進行較核
<br>
<br>urg_ptr如果urg=1,那么指出緊急數據對于歷史數據開始的序列號的偏移值
<br>
<br>關于TCP協議的詳細情況,請查看 RFC793
<br>
<br>
<br>7.6 TCP連接的建立
<br>TCP協議是一種可靠的連接,為了保證連接的可靠性,TCP的連接要分為幾個步驟.我們把這個連接過程稱為"三次握手".
<br>
<br>下面我們從一個實例來分析建立連接的過程.
<br>
<br>第一步客戶機向服務器發送一個TCP數據包,表示請求建立連接. 為此,客戶端將數據包的SYN位設置為1,并且設置序列號seq=1000(我們假設為1000).
<br>
<br>第二步服務器收到了數據包,并從SYN位為1知道這是一個建立請求的連接.于是服務器也向客戶端發送一個TCP數據包.因為是響應客戶機的請求,于是服務器設置ACK為1,sak_seq=1001(1000+1)同時設置自己的序列號.seq=2000(我們假設為2000).
<br>
<br>第三步客戶機收到了服務器的TCP,并從ACK為1和ack_seq=1001知道是從服務器來的確認信息.于是客戶機也向服務器發送確認信息.客戶機設置ACK=1,和ack_seq=2001,seq=1001,發送給服務器.至此客戶端完成連接.
<br>
<br>最后一步服務器受到確認信息,也完成連接.
<br>
<br>通過上面幾個步驟,一個TCP連接就建立了.當然在建立過程中可能出現錯誤,不過TCP協議可以保證自己去處理錯誤的.
<br>
<br>
<br> 說一說其中的一種錯誤.
<br> 聽說過DOS嗎?(可不是操作系統啊).今年春節的時候,美國的五大網站一起受到攻擊.攻擊者用的就是DOS(拒絕式服務)方式.概括的說一下原理.
<br> 客戶機先進行第一個步驟.服務器收到后,進行第二個步驟.按照正常的TCP連接,客戶機應該進行第三個步驟.
<br>不過攻擊者實際上并不進行第三個步驟.因為客戶端在進行第一個步驟的時候,修改了自己的IP地址,就是說將一個實際上不存在的IP填充在自己IP數據包的發送者的IP一欄.這樣因為服務器發的IP地址沒有人接收,所以服務端會收不到第三個步驟的確認信號,這樣服務務端會在那邊一直等待,直到超時.
<br>這樣當有大量的客戶發出請求后,服務端會有大量等待,直到所有的資源被用光,而不能再接收客戶機的請求.
<br>這樣當正常的用戶向服務器發出請求時,由于沒有了資源而不能成功.于是就出現了春節時所出現的情況.
<br></font></td></tr><tr><td><hr></td></tr><form method=post action=/cgi-bin/find.cgi><tr><td><b>相關文章</b> 關鍵詞 <input type=text name=key value='Linux網絡編程'> <input type=submit value=搜索></td></tr></form><tr><td><a href=/a4/b7/20010508/112209.html>Linux網絡編程--6. 高級套接字函數</a> <small>(2001-05-08 11:22:09)</small></font><br><a href=/a4/b7/20010508/112131.html>Linux網絡編程--5. 用戶數據報發送</a> <small>(2001-05-08 11:21:31)</small></font><br><a href=/a4/b7/20010508/112052.html>Linux網絡編程--4. 完整的讀寫函數</a> <small>(2001-05-08 11:20:52)</small></font><br><a href=/a4/b7/20010508/112014.html>Linux網絡編程--3. 服務器和客戶機的信息函數</a> <small>(2001-05-08 11:20:14)</small></font><br><a href=/a4/b7/20010508/111934.html>Linux網絡編程--2. 初等網絡函數介紹(TCP)</a> <small>(2001-05-08 11:19:34)</small></font><br><a href=/a4/b7/20010508/111655.html>Linux網絡編程--1. Linux網絡知識介紹</a> <small>(2001-05-08 11:16:55)</small></font><br></td></tr><tr><td> </td></tr></table></td></tr><tr> <td width="100%" height="2" colspan="5" bgcolor="#D09F0D"><img src="/images/c.gif" width=1 height=1></td> </tr><tr> <td width="100%" height="40" colspan="5" valign=top><p align="center"><font color=#ffffff>© 樊強制作 歡迎分享 2001 </font></p></td> </tr></table></center></div><img src="/cgi-bin/pagehit.cgi?filename=a4/b7/20010508/112240.html" width=1 height=1></body></html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -