C/C++ socket編程教程:1天玩轉socket通信技術?
一些基本概念
socket:套接字,計算機之間進行通信的一種約定。
網絡編程:編寫程序使兩臺聯網的計算機相互交換數據。
典型應用:Web 服務器和瀏覽器。瀏覽器獲取用戶輸入的URL,向服務器發起請求,服務器分析接收到的URL,將對應的網頁內容返回給瀏覽器,瀏覽器再經過解析和渲染,就將文字、圖片、視頻等元素呈現給用戶。
確定計算機位置:IP地址。有了IP地址可以找到目標計算機,但仍不能通信,端口號用來區分不同的網絡程序(web ftp smtp)。端口(Port)是一個虛擬的、邏輯上的概念。
協議(Protocol)就是網絡通信的約定,通信的雙方必須都遵守才能正常收發數據。
數據傳輸方式:???????????????????????????????????????????????????????????????????????????????????????????????????????????????
1) SOCK_STREAM 表示面向連接的數據傳輸方式(http協議 網頁)??????????? ? ? ? ? ? ? ? ? ? ? ?? ???
2) SOCK_DGRAM 表示無連接的數據傳輸方式(QQ視頻和語言)
socket() 函數用來創建套接字,確定套接字的各種屬性,然后服務器端要用 bind() 函數將套接字與特定的IP地址和端口綁定起來,只有這樣,流經該IP地址和端口的數據才能交給套接字處理;而客戶端要用 connect() 函數建立連接。
對于服務器端程序,使用 bind() 綁定套接字后,還需要使用 listen() 函數讓套接字進入被動監聽狀態,再調用 accept() 函數,就可以隨時響應客戶端的請求了。listen() 只是讓套接字進入監聽狀態,并沒有真正接收客戶端請求,listen() 后面的代碼會繼續執行,直到遇到 accept()。accept() 會阻塞程序執行(后面代碼不能被執行),直到有新的請求到來。
可以使用 write()/send() 函數發送數據,使用 read()/recv() 函數接收數據。數據的接收和發送是無關的,read()/recv() 函數不管數據發送了多少次,都會盡可能多的接收數據。也就是說,read()/recv() 和 write()/send() 的執行次數可能不同。例如,write()/send() 重復執行三次,每次都發送字符串"abc",那么目標機器上的 read()/recv()可能分三次接收,每次都接收"abc";也可能分兩次接收,第一次接收"abcab",第二次接收"cabc";也可能一次就接收到字符串"abcabcabc"。
數據的“粘包”問題:客戶端發送的多個數據包被當做一個數據包接收。也稱數據的無邊界性,read()/recv() 函數不知道數據包的開始或結束標志(實際上也沒有任何開始或結束標志),只把它們當做連續的數據流來處理。
TCP套接字的阻塞模式。所謂阻塞,就是上一步動作沒有完成,下一步動作將暫停,直到上一步動作完成后才能繼續,以保持同步性。每個 socket 被創建后,都會分配兩個緩沖區,輸入緩沖區和輸出緩沖區,write()/send(),read()/recv()可能會發生阻塞。
close()/closesocket()和shutdown()。
shutdown() 用來關閉連接,而不是套接字,不管調用多少次 shutdown(),套接字依然存在,直到調用 close() / closesocket() 將套接字從內存清除。
TCP三次握手
TCP(Transmission Control Protocol,傳輸控制協議)是一種面向連接的、可靠的、基于字節流的通信協議,數據在傳輸前要建立連接,傳輸完畢后還要斷開連接。
Seq:序號
Ack:確認號
SYN:標志位,表示該數據包用來建立連接
三次握手的關鍵是要確認對方收到了自己的數據包,這個目標就是通過“確認號(Ack)”字段實現的。計算機會記錄下自己發送的數據包序號 Seq,待收到對方的數據包后,檢測“確認號(Ack)”字段,看Ack = Seq + 1是否成立,如果成立說明對方正確收到了自己的數據包。
主機A分2次(分2個數據包)向主機B傳遞200字節的過程。
注意Ack 號為 1301 而不是 1201,原因在于 Ack 號的增量為傳輸的數據字節數。假設每次 Ack號不加傳輸的字節數,這樣雖然可以確認數據包的傳輸,但無法明確100字節全部正確傳遞還是丟失了一部分,比如只傳遞了80字節。
因此按如下的公式確認Ack 號:Ack號 = Seq號 + 傳遞的字節數 + 1
TIME_WAIT 要等待 2MSL(Maximum Segment Lifetime,報文最大生存時間) 才會進入 CLOSED 狀態。ACK 包到達服務器需要 MSL 時間,服務器重傳 FIN 包也需要 MSL時間,2MSL 是數據包往返的最大時間,如果 2MSL 后還未收到服務器重傳的 FIN 包,就說明服務器已經收到了 ACK 包。
UDP 是非連接的傳輸協議,沒有建立連接和斷開連接的過程。UDP不必調用 listen() 和 accept() 函數。UDP中只有創建套接字的過程和數據交換的過程。