Socket實現(xiàn)簡單的聊天功能,我們先來看下效果:



通過這張圖,我們更容易的去理解這些API,客戶端和服務(wù)端的不同點就是建立連接部分。服務(wù)端需要bind listen accept ,多個客戶端可以連接一個服務(wù)端。
? ? 1>? domain:協(xié)議域,又稱協(xié)議族(family)。常用的協(xié)議族有AF_INET、AF_INET6、AF_LOCAL(或稱AF_UNIX,Unix域Socket)、AF_ROUTE等。協(xié)議族決定了socket的地址類型。
?? ? 2> type:指定Socket類型。常用的socket類型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式Socket(SOCK_STREAM)是一種面向連接的Socket,針對于面向連接的TCP服務(wù)應(yīng)用。數(shù)據(jù)報式Socket(SOCK_DGRAM)是一種無連接的Socket,對應(yīng)于無連接的UDP服務(wù)應(yīng)用。
?? ? 3>?protocol:指定協(xié)議。常用協(xié)議有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分別對應(yīng)TCP傳輸協(xié)議、UDP傳輸協(xié)議、STCP傳輸協(xié)議、TIPC傳輸協(xié)議。
?? ? 注意:1.type和protocol不可以隨意組合,如SOCK_STREAM不可以跟IPPROTO_UDP組合。當?shù)谌齻€參數(shù)為0時,會自動選擇第二個參數(shù)類型對應(yīng)的默認協(xié)議。
?? ? 返回值:?如果調(diào)用成功就返回新創(chuàng)建的套接字的描述符,如果失敗就返回INVALID_SOCKET(Linux下失敗返回-1)?*/
? ? ?socket(AF_INET, SOCK_STREAM, 0);
1>?套接字描述符
2>?指向數(shù)據(jù)結(jié)構(gòu)sockaddr的指針,其中包括目的端口和IP地址
3>?參數(shù)二sockaddr的長度,可以通過sizeof(struct sockaddr)獲得
返回值:成功則返回0,失敗返回非0,錯誤碼GetLastError()
?connect(self.mSocketId,(conststructsockaddr*)&socket_add,sizeof(socket_add));
? ? ?1> 套接字描述符
?? ? 2> 指向數(shù)據(jù)結(jié)構(gòu)sockaddr的指針,其中包括目的端口和IP地址
?? ? 3> sockaddr的長度,可以通過sizeof(struct sockaddr)獲得
? ? ?返回值:? 成功則返回0,失敗返回非0,錯誤碼GetLastError()。
? ? ?bind(mSocketId, (const?struct?sockaddr?*)&socket_add,?sizeof(socket_add));
????1>?套接字描述符
?????2> 最大支持連接數(shù)
?? ? 返回值:如果失敗則返回?-1?
????listen(mSocketId, MaxConnectCount);
????1> 客戶端socket
?? ? 2> 指向數(shù)據(jù)結(jié)構(gòu)sockaddr的指針
?? ? 返回值:失敗則返回?-1 SOCKET_ERROR,成功返回客戶端編號
? ? ?accept(mSocketId, (structsockaddr*)&client_addr, &addr_length);
?? ? ?1>? ?一個用于標識已連接套接口的描述字。
?? ? ?2>? 包含待發(fā)送數(shù)據(jù)的緩沖區(qū)。
?? ? ?3>? 緩沖區(qū)中數(shù)據(jù)的長度。
? ? ??4>? 調(diào)用執(zhí)行方式。
? ? ? 返回值:如果成功,則返回發(fā)送的字節(jié)數(shù),失敗則返回SOCKET_ERROR
? ? ? 一個中文對應(yīng) 3 個字節(jié)!UTF8 編碼!
? ? ??send(mSocketId, send_msg, strlen(send_msg), 0);
????1> 客戶端socket????????
?? ? 2> 接收內(nèi)容緩沖區(qū)地址
?? ? 3> 接收內(nèi)容緩存區(qū)長度
?? ? 4> 接收方式,0表示阻塞,必須等待服務(wù)器返回數(shù)據(jù)
? ? ?返回值:如果成功,則返回讀入的字節(jié)數(shù),失敗則返回?-1?SOCKET_ERROR
? ? ? recv(mSocketId, buffer,sizeof(buffer),0);
TCP三次握手
連接上Socket后,發(fā)消息時,用Wireshark網(wǎng)絡(luò)封包分析工具,抓到以下數(shù)據(jù)。我們來看一下TCP的三次握手。
TCP是因特網(wǎng)中的傳輸層協(xié)議,使用三次握手協(xié)議建立連接。
當主動方發(fā)出SYN連接請求后,等待對方回答TCP的三次握手SYN+ACK ,并最終對對方的 SYN 執(zhí)行 ACK 確認。
這種建立連接的方法可以防止產(chǎn)生錯誤的連接,TCP使用的流量控制協(xié)議是可變大小的滑動窗口協(xié)議。
IP層協(xié)議屬于不可靠的協(xié)議,IP層并不關(guān)心數(shù)據(jù)是否發(fā)送到了對端,TCP通過確認機制來保證數(shù)據(jù)傳輸?shù)目煽啃?

TCP三次握手的過程如下:
(1)客戶端發(fā)送SYN(SEQ=x)報文給服務(wù)器端,進入SYN_SEND狀態(tài)。
(2)服務(wù)器端收到SYN報文,回應(yīng)一個SYN (SEQ=y)ACK(ACK=x+1)報文,進入SYN_RECV狀態(tài)。
(3)客戶端收到服務(wù)器端的SYN報文,回應(yīng)一個ACK(ACK=y+1)報文,進入Established狀態(tài)。
TCP Window Update 滑動窗口,在一個文件傳輸?shù)臅r候, 數(shù)據(jù)接收方需要阻止它的TCP Window降為0, 意味著window填滿了. 如果一個TCP Window變?yōu)?了, 或者接近0了, 這就會警告數(shù)據(jù)發(fā)送方?jīng)]有更多空間來接受更多數(shù)據(jù)了.文件傳輸會停止, 直到收到一個update說明buffer已經(jīng)清空了.
Frame:Frame是幀,數(shù)據(jù)單元,對應(yīng)物理層。
LoopBack:對應(yīng)數(shù)據(jù)鏈路層,以太網(wǎng)卡等,這里用的本地回環(huán)地址LoopBack。
IPV4:對應(yīng)網(wǎng)絡(luò)層,IP協(xié)議(協(xié)議??梢韵胂蟪陕┒沸?,IP在中間作為上下層的連接點),Src:源地址 Dst:目標地址,IP層協(xié)議層無端口
TCP:進入TCP層,有端口,對應(yīng)傳輸層。
滑動窗口
用上面藍色線代表服務(wù)端,下面代表客戶端。中間箭頭代表發(fā)起和響應(yīng)的網(wǎng)絡(luò)請求。綠色框代表滑動窗口。
滑動窗口是控制接收以及同步數(shù)據(jù)范圍的,通知發(fā)送端目前接收的數(shù)據(jù)范圍,用于流量控制,接收端使用。
擁塞窗口是控制發(fā)送速率的,避免發(fā)的過多,發(fā)送端使用。
兩個窗口的維護是獨立的,滑動窗口主要由接收方反饋緩存情況來維護,擁塞窗口主要由發(fā)送方的擁塞控制算法檢測出的網(wǎng)絡(luò)擁塞程度來決定的。

TCP四次揮手
斷開連接時,用Wireshark網(wǎng)絡(luò)封包分析工具,抓到了TCP的四次揮手

(1) 關(guān)閉時首先調(diào)用close,稱該端執(zhí)行“主動關(guān)閉”(active close)。該端的TCP于是發(fā)送一個FIN分節(jié),表示數(shù)據(jù)發(fā)送完畢。
(2) 接收到這個FIN的對端執(zhí)行 “被動關(guān)閉”(passive close),這個FIN由TCP確認。
注意:FIN的接收也作為一個文件結(jié)束符(end-of-file)傳遞給接收端應(yīng)用進程,放在已排隊等候該應(yīng)用進程接收的任何其他數(shù)據(jù)之后,因為,F(xiàn)IN的接收意味著接收端應(yīng)用進程在相應(yīng)連接上再無額外數(shù)據(jù)可接收。
(3) 一段時間后,接收到這個文件結(jié)束符的應(yīng)用進程將調(diào)用close關(guān)閉它的套接字。這導致它的TCP也發(fā)送一個FIN。
(4) 接收這個最終FIN的原發(fā)送端TCP(即執(zhí)行主動關(guān)閉的那一端)確認這個FIN。
TCP 和 UDP
TCP:(傳輸控制協(xié)議)
TCP的優(yōu)點: 穩(wěn)定?TCP的可靠體現(xiàn)在TCP在傳遞數(shù)據(jù)之前,通過三次握手建立連接,形成傳輸數(shù)據(jù)的通道,四次揮手完成斷開,是可靠協(xié)議,安全送達。
在連接中進行大數(shù)據(jù)傳輸(數(shù)據(jù)大小不受限制)TCP保證數(shù)據(jù)順序,UDP不保證。
缺點:必須建立連接,效率會稍低。
應(yīng)用場景: 下載數(shù)據(jù)
UDP(用戶數(shù)據(jù)協(xié)議)
速度快,UDP沒有TCP的握手,UDP是一個無狀態(tài)的傳輸協(xié)議,不需要建立連接,所以它在傳遞數(shù)據(jù)時非???。
只管發(fā)送,不確認對方是否接收到,將數(shù)據(jù)及源和目的封裝成數(shù)據(jù)包中,每個數(shù)據(jù)報的大小限制在64k之間。
缺點:不需要建立連接,因此是不可靠協(xié)議,會丟包。
應(yīng)用場景:流媒體數(shù)據(jù)傳輸,直播時界面會模糊,馬賽克的感覺(數(shù)據(jù)丟幀)?QQ語音?QQ視頻?王者榮耀等也是UDP
OSI網(wǎng)絡(luò)模型(太官方不太懂,舉個例子一下就明白了)
物理層:主要定義物理設(shè)備標準,如網(wǎng)線的接口類型、光纖的接口類型、各種傳輸介質(zhì)的傳輸速率等。它的主要作用是傳輸比特流(就是1、0轉(zhuǎn)化為電流的強弱來進行傳輸,到達目的地后再轉(zhuǎn)化為1、0,也就是我們常說的數(shù)模轉(zhuǎn)換與模數(shù)轉(zhuǎn)換)。這一層的數(shù)據(jù)叫做比特。
例:數(shù)據(jù)在電線傳輸過程中,用電流的高低頻代表 01 二進制數(shù)據(jù),但是電信號容易收到影響(數(shù)據(jù)傳輸中需要打包,有種格式叫 :標準幀格式。物理層(電線)
數(shù)據(jù)鏈路層:定義了如何格式化數(shù)據(jù)以進行傳輸,以及如何讓控制對物理介質(zhì)的訪問。這一層通常還提供錯誤檢測和糾正,以確保數(shù)據(jù)的可靠傳輸。
例:?數(shù)據(jù)鏈路層(數(shù)據(jù)打包的過程)
網(wǎng)絡(luò)層:在位于不同地理位置的網(wǎng)絡(luò)中的兩個主力系統(tǒng)之間提供連接和路徑選擇。Internet的發(fā)展使得從世界各站點訪問信息的用戶數(shù)量大大增加,而網(wǎng)絡(luò)層正是管理這種連接的層。
例:網(wǎng)絡(luò)層( 選擇數(shù)據(jù)傳輸路徑,路由器)
傳輸層:定義了一些傳輸數(shù)據(jù)的協(xié)議和端口號(WWW端口80等),如:TCP(傳輸控制協(xié)議,傳輸效率低,可靠性強,用于傳輸可靠性要求高,數(shù)據(jù)量大的數(shù)據(jù)),UDP(用戶數(shù)據(jù)報協(xié)議,與TCP特性恰恰相反,用于傳輸可靠性要求不高,數(shù)據(jù)量小的數(shù)據(jù))。主要是將從下層接受的數(shù)據(jù)進行分段傳輸,到達目的地址后再進行重組。通常把這一層數(shù)據(jù)叫做段。
例:(有兩個協(xié)議TCP/UDP,保證數(shù)據(jù)正確送達)
會話層:通過傳輸層(端口號:傳輸端口與接受端口)建立數(shù)據(jù)傳輸?shù)耐贰V饕谀愕南到y(tǒng)之間發(fā)起會話或者接受會話請求(設(shè)備之間需要互相認識可以是IP也可以是MAC或者是主機名)。
例:(怎么接收你發(fā)來的數(shù)據(jù),需要建立網(wǎng)絡(luò)會話,對二進制數(shù)據(jù)解析,可以認為兩個交流的協(xié)議,設(shè)定一個協(xié)議例如HTTP)
表示層:可確保一個系統(tǒng)的應(yīng)用層所發(fā)送的信息可以被另外一個系統(tǒng)的應(yīng)用層讀取。
例:表示層(解析完數(shù)據(jù)需要表示,是文字還是圖片視頻)
應(yīng)用層:最靠近用戶的OSI層。這一層為用戶的應(yīng)用程序(例如電子郵件、文件傳輸和終端仿真)提供網(wǎng)絡(luò)服務(wù)
例:應(yīng)用層(表示完展示在UI界面上)

HTTP
在HTTP/1.1協(xié)議中,定義了8種發(fā)送http請求的方法
GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH
HTTP超文本傳輸協(xié)議,是短連接,是客戶端主動發(fā)送請求,服務(wù)器做出響應(yīng),服務(wù)器響應(yīng)之后,鏈接斷開。
HTTP是一個屬于應(yīng)用層面向?qū)ο蟮膮f(xié)議,HTTP有兩類報文:請求報文和響應(yīng)報文。
HTTP請求報文:一個HTTP請求報文由請求行、請求頭部、空行和請求數(shù)據(jù)4部分組成。
HTTP響應(yīng)報文:由三部分組成:狀態(tài)行、消息報頭、響應(yīng)正文。?
HTTPS:安全超文本傳輸協(xié)議(Secure Hypertext Transfer Protocol),它是一個安全通信通道,基于HTTP開發(fā),用于客戶計算機和服務(wù)器之間交換信息,使用安全套結(jié)字層(SSI)進行信息交換,即HTTP的安全版。
Scoket連接和HTTP連接的區(qū)別
HTTP協(xié)議是基于TCP連接的,是應(yīng)用層協(xié)議,主要解決如何包裝數(shù)據(jù)。Socket是對TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個調(diào)用接口(API),通過Socket,我們才能使用TCP/IP協(xié)議。
HTTP連接:短連接,客戶端向服務(wù)器發(fā)送一次請求,服務(wù)器響應(yīng)后連接斷開,節(jié)省資源。服務(wù)器不能主動給客戶端響應(yīng)(除非采用HTTP長連接技術(shù)),iPhone主要使用類NSURLConnection。
Socket連接:長連接,客戶端跟服務(wù)器端直接使用Socket進行連接,沒有規(guī)定連接后斷開,因此客戶端和服務(wù)器段保持連接通道,雙方可以主動發(fā)送數(shù)據(jù),一般多用于游戲.Socket默認連接超時時間是30秒,默認大小是8K(理解為一個數(shù)據(jù)包大小)。
HTTP:一般用于非實時連接的請求,只有客戶端主動向服務(wù)器發(fā)送請求時,服務(wù)器才能返回數(shù)據(jù)給客戶端。
XMPP:基于xml通訊的協(xié)議,基于TCP發(fā)送xml數(shù)據(jù),一般用于即時通信。?
GET和POST的區(qū)別:
GET請求:參數(shù)在地址后拼接,沒有請求數(shù)據(jù),不安全(因為所有參數(shù)都拼接在地址后面),不適合傳輸大量數(shù)據(jù)(長度有限制,為1024個字節(jié))。
GET提交、請求的數(shù)據(jù)會附在URL之后,即把數(shù)據(jù)放置在HTTP協(xié)議頭中。
以?分割URL和傳輸數(shù)據(jù),多個參數(shù)用&連接。如果數(shù)據(jù)是英文字母或數(shù)字,原樣發(fā)送,
如果是空格,轉(zhuǎn)換為+,如果是中文/其他字符,則直接把字符串用BASE64加密。
POST請求:參數(shù)在請求數(shù)據(jù)區(qū)放著,相對GET請求更安全,并且數(shù)據(jù)大小沒有限制。把提交的數(shù)據(jù)放置在HTTP包的包體中.
GET提交的數(shù)據(jù)會在地址欄顯示出來,而POST提交,地址欄不會改變。
傳輸數(shù)據(jù)的大小:
GET提交時,傳輸數(shù)據(jù)就會受到URL長度限制(1KB),POST由于不是通過URL傳值,理論上不受限。
安全性:
POST的安全性要比GET的安全性高;
通過GET提交數(shù)據(jù),用戶名和密碼將明文出現(xiàn)在URL上,比如登陸界面有可能被瀏覽器緩存
參考資料:https://objccn.io/issue-10-6/
SocketDemo:https://github.com/TeeMoYan/TMSocketDemo.git