該篇文章主要回顧--TCP/IP協(xié)議族中的TCP/UDP、HTTP;還有Socket。(--該文很干,醞釀了許久!你能耐心看完嗎?O_o)
我在這個文章中,列舉了常見的TCP/IP族中的協(xié)議,今天主角是--傳輸層協(xié)議。
傳輸層(Transport Layer)是OSI(七層模型)中最重要、最關(guān)鍵的一層,它負責(zé)總體的數(shù)據(jù)傳輸和數(shù)據(jù)控制的一層,傳輸層提供端到端(應(yīng)用會在網(wǎng)卡注冊一個端口號)的交換數(shù)據(jù)的機制,檢查分組編號與次序。傳輸層對其上三層如會話層等,提供可靠的傳輸服務(wù),對網(wǎng)絡(luò)層提供可靠的目的地站點信息。
TCP提供一對一的、面向連接的可靠通信服務(wù)。TCP建立連接,對發(fā)送的數(shù)據(jù)包進行排序和確認,并恢復(fù)在傳輸過程中丟失的數(shù)據(jù)包。與TCP不同,UDP提供一對一或一對多的、無連接的不可靠通信服務(wù)。
不論是TCP/IP還是在OSI參考模型中,任意相鄰兩層的下層為服務(wù)提供者,上層為服務(wù)調(diào)用者。下層為上層提供的服務(wù)可分為兩類:面向連接服務(wù)和無連接服務(wù)。
面向連接的網(wǎng)絡(luò)服務(wù)又稱為虛電路(Virtual Circuit)服務(wù),它具有網(wǎng)絡(luò)連接建立、數(shù)據(jù)傳輸和網(wǎng)絡(luò)連接釋放三個階段。是按順序傳輸可靠的報文分組方式,適用于指定對象、長報文、會話型傳輸要求。
面向連接服務(wù)以電話系統(tǒng)為模式。要和某個人通話,首先拿起電話,撥號碼,通話,然后掛斷。同樣在使用面向連接的服務(wù)時,用戶首先要建立連接,使用連接,然后釋放連接。連接本質(zhì)上像個管道:發(fā)送者在管道的一端放入物體,接收者在另一端按同樣的次序取出物體;其特點是收發(fā)的數(shù)據(jù)不僅順序一致,而且內(nèi)容也相同。--類似打電話
無連接網(wǎng)絡(luò)服務(wù)的兩實體之間的通信不需要事先建立好一個連接。無連接網(wǎng)絡(luò)服務(wù)有3種類型:數(shù)據(jù)報(Datagram)、確認交付(Confirmed Delivery)與請求回答(Request reply)。
無連接服務(wù)以郵政系統(tǒng)為模式。每個報文(信件)帶有完整的目的地址,并且每一個報文都獨立于其他報文,由系統(tǒng)選定的路線傳遞。在正常情況下,當兩個報文發(fā)往同一目的地時,先發(fā)的先到。但是,也有可能先發(fā)的報文在途中延誤了,后發(fā)的報文反而先收到;而這種情況在面向連接的服務(wù)中是絕對不可能發(fā)生的。--類似發(fā)短信
三次握手示意圖:
TCP工作過程比較復(fù)雜,包括的內(nèi)容如下。
UDP全稱是User Datagram Protocol,中文名為用戶數(shù)據(jù)報協(xié)議。UDP 提供無連接的網(wǎng)絡(luò)服務(wù),該服務(wù)對消息中傳輸?shù)臄?shù)據(jù)提供不可靠的、最大努力傳送。這意味著它不保證數(shù)據(jù)報的到達,也不保證所傳送數(shù)據(jù)包的順序是否正確。
我最初就有一個疑惑:“既然UDP是一種不可靠的網(wǎng)絡(luò)協(xié)議,那么還有什么使用價值或必要呢?”
在有些情況下UDP可能會變得非常有用。因為UDP具有TCP所望塵莫及的速度優(yōu)勢。雖然TCP中植入了各種安全保障功能,但是在實際執(zhí)行的過程中會占用大量的系統(tǒng)開銷,無疑使速度受到嚴重的影響。反觀UDP由于排除了信息可靠傳遞機制,將安全和排序等功能移交給上層應(yīng)用來完成,極大地降低了執(zhí)行時間,使速度得到了保證。
TCP和UDP都是IP層面的傳輸協(xié)議,是IP與上層之間的處理接口。TCP和UDP端口號被設(shè)計來區(qū)分運行在單個設(shè)備上的多重應(yīng)用程序的IP地址。由于同一臺計算機上可能會運行多個網(wǎng)絡(luò)應(yīng)用程序,所以計算機需要確保目標計算機上接收源主機數(shù)據(jù)包的軟件應(yīng)用程序的正確性,以及響應(yīng)能夠被發(fā)送到源主機的正確應(yīng)用程序上。該過程正是通過使用TCP或UDP端口號來實現(xiàn)的。
--即每一個應(yīng)用都會在網(wǎng)卡上注冊一個端口號用來區(qū)分同一臺設(shè)備上應(yīng)用的之間的通信在TCP和UDP頭部分,有“源端口”和“目標端口”段,主要用于顯示發(fā)送和接收過程中的身份識別信息。IP 地址和端口號合在一起被稱為“套接字”。TCP端口比較復(fù)雜,其工作方式與UDP端口不同。UDP端口對于基于UDP的通信作為單一消息隊列和網(wǎng)絡(luò)端點來操作,而所有TCP通信的終點都是唯一的連接。每個TCP連接由兩個端點唯一識別。由于所有TCP連接由兩對 IP 地址和TCP端口唯一識別(每個所連主機都有一個地址/端口對),因此每個TCP服務(wù)器端口都能提供對多個連接的共享訪問
再看一下IP數(shù)據(jù)包和TCP/UDP的數(shù)據(jù)包數(shù)據(jù)包.png
超文本傳輸協(xié)議(HTTP,HyperText Transfer Protocol)是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議。
http協(xié)議規(guī)定了客戶端和服務(wù)器之間的數(shù)據(jù)傳輸格式.
簡單快速:
http協(xié)議簡單,通信速度很快;
靈活:
http協(xié)議允許傳輸任意類型的數(shù)據(jù);
短連接:
http協(xié)議限制每次連接只處理一個請求,服務(wù)器對客戶端的請求作出響應(yīng)后,馬上斷開連接.這種方式可以節(jié)省傳輸時間.
請求:客戶端向服務(wù)器索要數(shù)據(jù).
http協(xié)議規(guī)定:一個完整的http請求包含'請求行','請求頭','請求體'三個部分;
Accept: text/html ( 客戶端所能接收的數(shù)據(jù)類型 )
Accept-Language: zh-cn ( 客戶端的語言環(huán)境 )
Accept-Encoding: gzip( 客戶端支持的數(shù)據(jù)壓縮格式 )
Host: m.baidu.com( 客戶端想訪問的服務(wù)器主機地址 )
User-Agent: Mozilla/5.0(Macintosh;Intel Mac OS X10.10 rv:37.0) Gecko/20100101Firefox/37.0( 客戶端的類型,客戶端的軟件環(huán)境 )
響應(yīng):服務(wù)器返回客戶端想要的數(shù)據(jù)
http協(xié)議規(guī)定:一個完整的http響應(yīng)包含'狀態(tài)行','響應(yīng)頭','實體內(nèi)容'三個部分;
Content-Encoding: gzip(服務(wù)器支持的數(shù)據(jù)壓縮格式) Content-Length: 1528(返回數(shù)據(jù)的長度)
Content-Type:application/xhtml xml;charset=utf-8(返回數(shù)據(jù)的類型)
Date: Mon,15Jun201509:06:46GMT(響應(yīng)的時間) Server: apache (服務(wù)器類型)
發(fā)送http請求
在iOS開發(fā)中,發(fā)送http請求的方案有很多,常見的有如下幾種:
NSURLConnection:
用法簡單,古老經(jīng)典的一種方案.
NSURLSession:
iOS7以后推出的技術(shù),功能NSURLConnection更加強大.
CFNetWork:NSURL的底層,純C語言,一般不用.
http協(xié)議定義了很多方法對應(yīng)不同的資源操作,其中最常用的是GET和POST方法。
eg:GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH
增:PUT
刪:DELETE
改:POST
查:GET
因為GET和POST可以實現(xiàn)上述所有操作,所以,在現(xiàn)實開發(fā)中,GET和POST方法使用的最為廣泛,除此以外HEAD請求使用頻率也比較高;
在請求URL后面以?的形式跟上發(fā)給服務(wù)器的參數(shù),參數(shù)以'參數(shù)名'='參數(shù)值'的形式拼接,多個參數(shù)之間用&分隔;
GET的本質(zhì)是從服務(wù)器得到數(shù)據(jù),效率更高.并且GET請求可以被緩存.
注意:GET的長度是有限制的,不同的瀏覽器有不同的長度限制,一般在2~8K之間;
POST的本質(zhì)是向服務(wù)器發(fā)送數(shù)據(jù),也可以獲得服務(wù)器處理之后的結(jié)果,效率不如GET.POST請求不可以被緩存,每次刷新之后都需要重新提交表單.
發(fā)送給服務(wù)器的參數(shù)全部放在'請求體'中;
理論上,POST傳遞的數(shù)據(jù)量沒有限制.
注意:所有涉及到用戶隱私的數(shù)據(jù)(密碼/銀行卡號等...)都要用POST的方式傳遞.
HEAD方法通常用在下載文件之前,獲取遠程服務(wù)器的文件信息!相比于GET請求,不會下載文件數(shù)據(jù),只獲得響應(yīng)頭信息!
一般,使用HEAD方法的目的是提前告訴用戶下載文件的信息,由用戶確定是否下載文件!所以, HEAD方法,最好發(fā)送同步請求!
1xx:信息響應(yīng)類,表示接收到請求并且繼續(xù)處理
2xx:處理成功響應(yīng)類,表示動作被成功接收、理解和接受
3xx:重定向響應(yīng)類,為了完成指定的動作,必須接受進一步處理
4xx:客戶端錯誤,客戶請求包含語法錯誤或者是不能正確執(zhí)行
5xx:服務(wù)端錯誤,服務(wù)器不能正確執(zhí)行一個正確的請求;
詳細描述:狀態(tài)碼
- 內(nèi)存共享(
munmap()
);- 消息和隊列;
- 管道(匿名管道
pipe()
和命名管道mkfifo()
);- 信號量(
P V
操作);- RPC remote protocol control
- 本地Socket;
本地進程間通信(IPC)通過PID(在終端中輸入ps -ef可查看PID)可以唯一確定彼此,然后通過共享內(nèi)存,消息隊列來通;網(wǎng)絡(luò)上的兩個進程確定彼此需要IP與端口號,通過傳輸層(TCP/UDP)協(xié)議進行通信;
這就是網(wǎng)絡(luò) Socket 。socket可以理解為:在TCP/UDP 加一個端口(在網(wǎng)卡注冊的,還記得吧)綁定。
- 在同一個設(shè)備上,兩個進程如果需要進行通訊最基本的一個前提能能夠唯一的標示一個進程,在本地進程通訊中可以使用PID來唯一標示一個進程;
- PID只在本地唯一,網(wǎng)絡(luò)中的兩個進程PID沖突幾率很大,此時顯然不行了,怎么辦?
IP層的ip地址可以唯一標示主機,而TCP層協(xié)議和端口號可以唯一標示主機的一個進程,所以可以利用ip地址+協(xié)議+端口號唯一標示網(wǎng)絡(luò)中的一個進程。
Socket通信就是一種確定了端口號的TCP/IP通信,或者說Socket通信與IP通信差別就是端口確定,協(xié)議確定。
用一張圖表達一下:
端口的打開是雙方的,在C/S(Client&&Server)結(jié)構(gòu)的TCP連接中不僅僅要注意到S的端口(監(jiān)聽的),實際上C也開了一個端口,而C端的端口是動態(tài)端口,TCP連接建立的時候,C端的端口會在三次握手結(jié)束后確定,動態(tài)打開一個,這個端口不受用戶/程序員的控制。
一張經(jīng)典的Socket C/S的步驟圖。
1. 導(dǎo)入頭文件#import <sys/socket.h> //socket相關(guān)#import <netinet/in.h> //internet相關(guān)#import <arpa/inet.h> //地址解析協(xié)議相關(guān)2. socket(創(chuàng)建) int socket(int, int, int); /** 參數(shù) 第一個int:domain: 協(xié)議域,AF_INET(IPV4的網(wǎng)絡(luò)開發(fā)) 第二個int:type: Socket 類型, SOCK_STREAM(TCP)/SOCK_DGRAM(UDP,報文) 第三個int:protocol: IPPROTO_TCP,協(xié)議,如果輸入0,可以根據(jù)第二個參數(shù),自動選擇協(xié)議 返回值 socket,如果 > 0 就表示成功 */3. connection (連接到“服務(wù)器) connect(int, const struct sockaddr *, socklen_t) /** 參數(shù) 1> 客戶端socket 2> 指向數(shù)據(jù)結(jié)構(gòu)sockaddr的指針,其中包括目的端口和IP地址 服務(wù)器的'結(jié)構(gòu)體'地址,C語言沒有對象 3> 結(jié)構(gòu)體數(shù)據(jù)長度 返回值 0 成功/其他 錯誤代號 */4. write(發(fā)送數(shù)據(jù)) send(int, const void *, size_t, int) /** 參數(shù) 1> 客戶端socket 2> 發(fā)送內(nèi)容地址 void * == id 3> 發(fā)送內(nèi)容長度 4> 發(fā)送方式標志,一般為0 返回值 如果成功,則返回發(fā)送的字節(jié)數(shù),失敗則返回SOCKET_ERROR */5. read (接收) recv(int, void *, size_t, int) /** 參數(shù) 第一個int :創(chuàng)建的socket void *:接收內(nèi)容的地址 size_t:接收內(nèi)容的長度 第二個int.:接收數(shù)據(jù)的標記 0,就是阻塞式,一直等待服務(wù)器的數(shù)據(jù) 返回值 接收到的數(shù)據(jù)長度 */6. close close(int); int:就是創(chuàng)建的socket
按照上面5個步驟就可以寫一個socket的通信的小demo:
寫好的已經(jīng)放在了我的github;
此時沒有寫服務(wù)端,怎么測試?
可利用:nc -lk 端口號:始終監(jiān)聽本地計算機此端口的數(shù)據(jù)。
eg:nc -lk 6666;
操作步驟gif
1、監(jiān)聽 6666端口
2、connettion;
3、發(fā)送socket
;服務(wù)器接收到socket
;
4、服務(wù)端send :hello socket;
socket服務(wù)端下次再談!
以上就是本次回顧。
聯(lián)系客服