socket編程基礎知識


網絡編程就是編寫程序使兩台聯網的計算機相互交換數據。這就是全部內容了嗎?是的!網絡編程要比想象中的簡單許多。

那么,這兩台計算機之間用什么傳輸數據呢?首先需要物理連接。如今大部分計算機都已經連接到互聯網,因此不用擔心這一點。

在此基礎上,只需要考慮如何編寫數據傳輸程序。但實際上這點也不用愁,因為操作系統已經提供了 socket。即使對網絡數據傳輸的原理不太熟悉,我們也能通過 socket 來編程。

什么是 socket?

socket 的原意是“插座”,在計算機通信領域,socket 被翻譯為“套接字”,它是計算機之間進行通信的一種約定或一種方式。通過 socket 這種約定,一台計算機可以接收其他計算機的數據,也可以向其他計算機發送數據。

我們把插頭插到插座上就能從電網獲得電力供應,同樣,為了與遠程計算機進行數據傳輸,需要連接到因特網,而 socket 就是用來連接到因特網的工具。

socket是什么?


socket 的典型應用就是 Web 服務器和瀏覽器:瀏覽器獲取用戶輸入的 URL,向服務器發起請求,服務器分析接收到的 URL,將對應的網頁內容返回給瀏覽器,瀏覽器再經過解析和渲染,就將文字、圖片、視頻等元素呈現給用戶。

學習 socket,也就是學習計算機之間如何通信,並編寫出實用的程序。

UNIX/Linux 中的 socket 是什么?

在 UNIX/Linux 系統中,為了統一對各種硬件的操作,簡化接口,不同的硬件設備也都被看成一個文件。對這些文件的操作,等同於對磁盤上普通文件的操作。

你也許聽很多高手說過,UNIX/Linux 中的一切都是文件!那個家伙說的沒錯。

為了表示和區分已經打開的文件,UNIX/Linux 會給每個文件分配一個 ID,這個 ID 就是一個整數,被稱為文件描述符(File Descriptor)。例如:

  • 通常用 0 來表示標准輸入文件(stdin),它對應的硬件設備就是鍵盤;
  • 通常用 1 來表示標准輸出文件(stdout),它對應的硬件設備就是顯示器。


UNIX/Linux 程序在執行任何形式的 I/O 操作時,都是在讀取或者寫入一個文件描述符。一個文件描述符只是一個和打開的文件相關聯的整數,它的背后可能是一個硬盤上的普通文件、FIFO、管道、終端、鍵盤、顯示器,甚至是一個網絡連接。

請注意,網絡連接也是一個文件,它也有文件描述符!你必須理解這句話。

我們可以通過 socket() 函數來創建一個網絡連接,或者說打開一個網絡文件,socket() 的返回值就是文件描述符。有了文件描述符,我們就可以使用普通的文件操作函數來傳輸數據了,例如:

  • 用 read() 讀取從遠程計算機傳來的數據;
  • 用 write() 向遠程計算機寫入數據。


你看,只要用 socket() 創建了連接,剩下的就是文件操作了,網絡編程原來就是如此簡單!

WIndow 系統中的 socket 是什么?

Windows 也有類似“文件描述符”的概念,但通常被稱為“文件句柄”。因此,本教程如果涉及 Windows 平台將使用“句柄”,如果涉及 Linux 平台則使用“描述符”。

與 UNIX/Linux 不同的是,Windows 會區分 socket 和文件,Windows 就把 socket 當做一個網絡連接來對待,因此需要調用專門針對 socket 而設計的數據傳輸函數,針對普通文件的輸入輸出函數就無效了

 

套接字有哪些類型?socket有哪些類型?

先介紹主要的兩種:

流格式套接字(SOCK_STREAM)

流格式套接字(Stream Sockets)也叫“面向連接的套接字”,在代碼中使用 SOCK_STREAM 表示。

SOCK_STREAM 是一種可靠的、雙向的通信數據流,數據可以准確無誤地到達另一台計算機,如果損壞或丟失,可以重新發送。

流格式套接字有自己的糾錯機制,在此我們就不討論了。

SOCK_STREAM 有以下幾個特征:

  • 數據在傳輸過程中不會消失;
  • 數據是按照順序傳輸的;
  • 數據的發送和接收不是同步的(有的教程也稱“不存在數據邊界”)。


可以將 SOCK_STREAM 比喻成一條傳送帶,只要傳送帶本身沒有問題(不會斷網),就能保證數據不丟失;同時,較晚傳送的數據不會先到達,較早傳送的數據不會晚到達,這就保證了數據是按照順序傳遞的

為什么流格式套接字可以達到高質量的數據傳輸呢?這是因為它使用了 TCP 協議(The Transmission Control Protocol,傳輸控制協議),TCP 協議會控制你的數據按照順序到達並且沒有錯誤。

你也許見過 TCP,是因為你經常聽說“TCP/IP”。TCP 用來確保數據的正確性,IP(Internet Protocol,網絡協議)用來控制數據如何從源頭到達目的地,也就是常說的“路由”。

那么,“數據的發送和接收不同步”該如何理解呢?

假設傳送帶傳送的是水果,接收者需要湊齊 100 個后才能裝袋,但是傳送帶可能把這 100 個水果分批傳送,比如第一批傳送 20 個,第二批傳送 50 個,第三批傳送 30 個。接收者不需要和傳送帶保持同步,只要根據自己的節奏來裝袋即可,不用管傳送帶傳送了幾批,也不用每到一批就裝袋一次,可以等到湊夠了 100 個水果再裝袋。

流格式套接字的內部有一個緩沖區(也就是字符數組),通過 socket 傳輸的數據將保存到這個緩沖區。接收端在收到數據后並不一定立即讀取,只要數據不超過緩沖區的容量,接收端有可能在緩沖區被填滿以后一次性地讀取,也可能分成好幾次讀取。

也就是說,不管數據分幾次傳送過來,接收端只需要根據自己的要求讀取,不用非得在數據到達時立即讀取。傳送端有自己的節奏,接收端也有自己的節奏,它們是不一致的。

流格式套接字有什么實際的應用場景嗎?瀏覽器所使用的 http 協議就基於面向連接的套接字,因為必須要確保數據准確無誤,否則加載的 HTML 將無法解析。

數據報格式套接字(SOCK_DGRAM)

數據報格式套接字(Datagram Sockets)也叫“無連接的套接字”,在代碼中使用 SOCK_DGRAM 表示。

計算機只管傳輸數據,不作數據校驗,如果數據在傳輸中損壞,或者沒有到達另一台計算機,是沒有辦法補救的。也就是說,數據錯了就錯了,無法重傳。

因為數據報套接字所做的校驗工作少,所以在傳輸效率方面比流格式套接字要高。

可以將 SOCK_DGRAM 比喻成高速移動的摩托車快遞,它有以下特征:

  • 強調快速傳輸而非傳輸順序;
  • 傳輸的數據可能丟失也可能損毀;
  • 限制每次傳輸的數據大小;
  • 數據的發送和接收是同步的(有的教程也稱“存在數據邊界”)。


眾所周知,速度是快遞行業的生命。用摩托車發往同一地點的兩件包裹無需保證順序,只要以最快的速度交給客戶就行。這種方式存在損壞或丟失的風險,而且包裹大小有一定限制。因此,想要傳遞大量包裹,就得分配發送。

將無連接套接字比喻成摩托車快遞


另外,用兩輛摩托車分別發送兩件包裹,那么接收者也需要分兩次接收,所以“數據的發送和接收是同步的”;換句話說,接收次數應該和發送次數相同。

總之,數據報套接字是一種不可靠的、不按順序傳遞的、以追求速度為目的的套接字。

數據報套接字也使用 IP 協議作路由,但是它不使用 TCP 協議,而是使用 UDP 協議(User Datagram Protocol,用戶數據報協議)。

QQ 視頻聊天和語音聊天就使用 SOCK_DGRAM 來傳輸數據,因為首先要保證通信的效率,盡量減小延遲,而數據的正確性是次要的,即使丟失很小的一部分數據,視頻和音頻也可以正常解析,最多出現噪點或雜音,不會對通信質量有實質的影響。

注意:SOCK_DGRAM 沒有想象中的糟糕,不會頻繁的丟失數據,數據錯誤只是小概率事件。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM