1. 程式人生 > >什麼是套接字Socket

什麼是套接字Socket

Q:什麼是套接字(Socket)?套接字(Socket)是什麼意思?

應用層通過傳輸層進行資料通訊時,TCP和UDP會遇到同時為多個應用程式程序提供併發服務的問題。多個TCP連線或多個應用程式程序可能需要通過同一個TCP協議傳輸資料。為了區別不同的應用程式程序和連線,許多計算機作業系統為應用程式與TCP/IP協議互動提供了稱為套接字(Socket)的介面,區分不同應用程式程序間的網路通訊和連線。

網路化的應用程式在開始任何通訊之前都必需要建立套接字。就像電話的插口一樣,沒有它就完全沒辦法通訊。

生成套接字,主要有3個引數:通訊的目的IP地址、使用的傳輸層協議(TCP或UDP)和使用的埠號。Socket原意是“插座”。通過將這3個引數結合起來,與一個“插座”Socket繫結,應用層就可以和傳輸層通過套接字介面,區分來自不同應用程式程序或網路連線的通訊,實現資料傳輸的併發服務。

Socket可以看成在兩個程式進行通訊連線中的一個端點,一個程式將一段資訊寫入Socket中,該Socket將這段資訊傳送給另外一個Socket中,使這段資訊能傳送到其他程式中。如圖:

我們來分析一下上圖,Host A上的程式A將一段資訊寫入Socket中,Socket的內容被Host A的網路管理軟體訪問,並將這段資訊通過Host A的網路介面卡傳送到Host B,Host B的網路介面卡接收到這段資訊後,傳送給Host B的網路管理軟體,網路管理軟體將這段資訊儲存在Host B的Socket中,然後程式B才能在Socket中閱讀這段資訊。

假設在圖中的網路中新增第三個主機Host C,那麼Host A怎麼知道資訊被正確傳送到Host B而不是被傳送到Host C中了呢?基於TCP/IP網路中的每一個主機均被賦予了一個唯一的IP地址,IP地址是一個32位的無符號整數,由於沒有轉變成二進位制,因此通常以小數點分隔,如:198.163.227.6,正如所見IP地址均由四個部分組成,每個部分的範圍都是0-255,以表示8位地址。

值得注意的是IP地址都是32位地址,這是IP協議版本4(簡稱Ipv4)規定的,目前由於IPv4地址已近耗盡,所以IPv6地址正逐漸代替Ipv4地址,Ipv6地址則是128位無符號整數。

假設第二個程式被加入圖中的網路的Host B中,那麼由Host A傳來的資訊如何能被正確的傳給程式B而不是傳給新加入的程式呢?這是因為每一個基於TCP/IP網路通訊的程式都被賦予了唯一的埠和埠號,埠是一個資訊緩衝區,用於保留Socket中的輸入/輸出資訊,埠號是一個16位無符號整數,範圍是0-65535,以區別主機上的每一個程式(埠號就像房屋中的房間號),低於256的短口號保留給標準應用程式,比如pop3的埠號就是110,每一個套接字都組合進了IP地址、埠、埠號,這樣形成的整體就可以區別每一個套接字。

要通過網際網路進行通訊,至少需要一對套接字,一個運行於客戶機端,稱之為ClientSocket,另一個運行於伺服器端,稱之為serverSocket。

根據連線啟動的方式以及本地套接字要連線的目標,套接字之間的連線過程可以分為三個步驟:伺服器監聽,客戶端請求,連線確認。

伺服器監聽:是伺服器端套接字並不定位具體的客戶端套接字,而是處於等待連線的狀態,實時監控網路狀態。

客戶端請求:是指由客戶端的套接字提出連線請求,要連線的目標是伺服器端的套接字。為此,客戶端的套接字必須首先描述它要連線的伺服器的套接字,指出伺服器端套接字的地址和埠號,然後就向伺服器端套接字提出連線請求。

連線確認:是指當伺服器端套接字監聽到或者說接收到客戶端套接字的連線請求,它就響應客戶端套接字的請求,建立一個新的執行緒,把伺服器端套接字的描述發給客戶端,一旦客戶端確認了此描述,連線就建立好了。而伺服器端套接字繼續處於監聽狀態,繼續接收其他客戶端套接字的連線請求。

套接字起源於20世紀70年代加州大學伯克利分校版本的Unix,即人們所說的BSD Unix。因此,有時人們也把套接字稱為“伯克利套接字”或“BSD套接字”。一開始,套接字被設計用在同一臺主機上多個應用程式之間的通訊。這也被稱作程序間通訊,或IPC。套接字有兩種,分別是基於檔案型的和基於網路型的。

Unix套接字是我們要介紹的第一個套接字家族。其“家族名”為AF_UNIX(在POSIX1.g標準中也叫AF_LOCAL),表示“地址家族:UNIX”。包括Python在內的大多數流行平臺上都使用術語“地址家族”及其縮寫“AF”。而老一點的系統中,地址家族被稱為“域”或“協議家族”,並使用縮寫“PF”而不是“AF”。同樣的,AF_LOCAL(在2000-2001年被列為標準)將會代替AF_UNIX。不過,為了向後相容,很多系統上,兩者是等價的。Python自己則仍然使用AF_UNIX。

由於兩個程序都執行在同一臺機器上,而且這些套接字是基於檔案的。所以,它們的底層結構是由檔案系統來支援的。這樣做相當有道理,因為,同一臺電腦上,檔案系統的確是不同的程序都能訪問的。

另一種套接字是基於網路的,它有自己的家族名字:AF_INET,或叫“地址家族:Internet”。還有一種地址家族AF_INET6被用於網際協議第6版(IPv6)定址上。還有一些其他的地址家族,不過,它們要麼是隻用在某個平臺上,要麼就是已經被廢棄,或是很少被使用,或是根本就還沒有實現。所有地址家族中,AF_INET是使用最廣泛的一個。Python 2.5中加入了一種Linux套接字的支援:AF_NETLINK(無連線(稍後講解))套接字家族讓使用者程式碼與核心程式碼之間的IPC可以使用標準BSD套接字介面。而且,相對之前那些往作業系統中加入新的系統呼叫、proc檔案系統支援或是“IOCTL”等複雜的方案來說,這種方法顯得更為精巧,更為安全。

Python只支援AF_UNIX,AF_NETLINK,和AF_INET家族。由於我們只關心網路程式設計,所以在本章的大部分時候,我們都只用AF_INET。

套接字地址:主機與埠

如果把套接字比做電話的插口—即通訊的最底層結構,那主機與埠就像區號與電話號碼的一對組合。有了能打電話的硬體還不夠,你還要知道你要打給誰,往哪打。一個因特網地址由網路通訊所必需的主機與埠組成。而且不用說,另一端一定要有人在聽才可以。否則,你就會聽到熟悉的聲音“對不起,您撥的是空號,請查詢後再撥”。你在上網的時候,可能也見過類似的情況,如“不能連線該伺服器。伺服器無響應或不可達”。

合法的埠號範圍為0~65535。其中,小於1024的埠號為系統保留埠。如果你所使用的是Unix作業系統,那麼就可以通過/etc/services檔案獲得保留的埠號(及其對應的服務/協議和套接字型別)。