熟知套接字和應用層
必須有一種方法讓你對指定的計算機打開連接,登錄上去,告訴它你需要什么文件,並且控制文件的傳輸。(如果你想到不同的應用,例如計算機郵件,某種類似的協議也是需要的。)這個是由“應用層協議”完成的。應用層協議位於 TCP/IP協議的頂部。也就是說,當他們需要發送一個消息,他們會把那個消息交給TCP層。TCP層確保它輸送到另一端。因為TCP層和IP層處理了所有的網絡方面的細節,應用層協議可以認為一個網絡連接是一個簡單的字節流,就像一個終端或一條電話線。
在探究關於應用程序的更多細節之前,我們必須描述一下怎么找到一個應用。 假設你想傳送一個文件到一台Internet地址為128.6.4.7電腦上。要開始這個過程 ,你需要的不僅僅是Internet地址。你必須連接到另一端的FTP服務器。一般而言 ,網絡程序專門用來完成一些特定的任務。大多數系統用不同的程序去處理文件傳輸,遠程終端登錄,郵件等等。當你連接到128.6.4.7時,你必須指定你要和 FTP服務器對話。這是通過每個服務器持有的熟知套接字來實現的。前面已經說過 TCP層用端口號來區別不同的會話。用戶程序通常使用或多或少的隨機產生的端口號。然而特定的端口號被指派給等待請求的程序。例如,如果你要傳送一個文件 ,你要啟動一個稱為“ftp”的程序。它將使用某個隨機數(假定為1234)來打開一個連接,這個隨機數就是它這端的端口號。然而它將指定21作為另一端的端口號。這是FTP服務器的正式端口號。注意,有兩個不同的程序與此有關。你運行 ftp在你這邊。這個程序被設計成用來接受從你的終端發出的命令並把他們傳遞到另一端。在另一台機器上與你會話的程序是FTP服務器。與其說它被設計為一台交互式的終端,還不如說它是被設計用來接受來自網絡連接的命令的程序。沒有必 要讓你的程序使用一個熟知套接字號,因為沒有人會去查找它。但是服務器必須 有熟知端口號,這樣子才能讓人們對它們打開連接並且開始向它們傳送命令。每個程序的正式端口號都取之於“已分配號碼”。
注意,一個連接實際上由一組4個數來描述:各端的Internet地址和各端的TCP層 端口號。每個數據報都包含所有這4個數在里邊。(Internet地址在IP頭里,TCP 層端口號在TCP頭里。)為了互相區別,任意兩個連接都不能擁有相同的一組數字 。但是只要其中的任何一個數字不同就足夠啦。例如,很有可能同一台機器的兩 個用戶要傳送文件到相同的另一台機器,這就可能形成具有以下參數的連接:
Internet地址 TCP 端口
連接 1 128.6.4.194, 128.6.4.7 1234(源), 21(目)
連接 2 128.6.4.194, 128.6.4.7 1235(源), 21(目)
既然有關相同的機器,Internet地址就是一樣的。因為它們都進行文件傳輸,所以連接的一端涉及FTP的熟知端口號。唯一不同的東西是用戶運行的程序的端口號 。這已經足以形成區別了。一般來說,至少連接的一端要求網絡軟件給它分配確保是唯一的端口號。通常這個由用戶端做,因為服務器必須使用熟知端口號碼。
TCP為實現多路復用使用了端口號。因為端口號是在各個TCP實體上獨立使用的,因此從網絡整體看來,端口號並非具有唯一性的標識符。構造套接號后,網絡上具有唯一性的IP地址和端口號結合在一起,才構成唯一能識別的標識符。
套接字基本概念
套接字是通信的基石,是支持TCP/IP協議的網絡通信的基本操作單元。可以將套接字看作不同主機間的進程進行雙向通信的端點,它構成了單個主機內及整個網絡間的編程界面。套接字存在於通信域中,通信域是為了處理一般的線程通過套接字通信而引進的一種抽象概念。套接字通常和同一個域中的套接字交換數據(數據交換也可能穿越域的界限,但這時一定要執行某種解釋程序)。各種進程使用這個相同的域互相之間用Internet協議簇來進行通信。
套接字可以根據通信性質分類,這種性質對於用戶是可見的。應用程序一般僅在同一類的套接字間進行通信。不過只要底層的通信協議允許,不同類型的套接字間也照樣可以通信。套接字有兩種不同的類型:流套接字和數據報套接字。
套接字工作原理
要通過互聯網進行通信,你至少需要一對套接字,其中一個運行於客戶機端,我們稱之為ClientSocket,另一個運行於服務器端,我們稱之為ServerSocket。
根據連接啟動的方式以及本地套接字要連接的目標,套接字之間的連接過程可以分為三個步驟:服務器監聽,客戶端請求,連接確認。
所謂服務器監聽,是服務器端套接字並不定位具體的客戶端套接字,而是處於等待連接的狀態,實時監控網絡狀態。
所謂客戶端請求,是指由客戶端的套接字提出連接請求,要連接的目標是服務器端的套接字。為此,客戶端的套接字必須首先描述它要連接的服務器的套接字,指出服務器端套接字的地址和端口號,然后就向服務器端套接字提出連接請求。
所謂連接確認,是指當服務器端套接字監聽到或者說接收到客戶端套接字的連接請求,它就響應客戶端套接字的請求,建立一個新的線程,把服務器端套接字的描述發給客戶端,一旦客戶端確認了此描述,連接就建立好了。而服務器端套接字繼續處於監聽狀態,繼續接收其他客戶端套接字的連接請求。
套接字工作過程:
1. 創建套接字並綁定
調用socket函數創建一個待使用的套接字。通過這個函數的參數定義了套接字的類型、網絡地址類型和使用的協議,具體參數的定義請參考例程和Microsoft MSDN,在這里我們就不具體論述了。
使用bind函數綁定套接字,通過它將創建好的套接字與本地地址和本地端口聯系起來。
一個完整的網絡通訊必須具備協議、本地地址、本地端口、遠地地址和遠地端口5個基本要素,在創建套接字時確定了協議類型,而在綁定套接字時確定本地地址和本地端口,遠地地址和遠地端口的確認需要通過調用下面討論的連接和通訊類函數實現。
2. 建立socket連接
在客戶端使用connect函數和服務器建立連接。
而在服務器端則使用listen監聽來自客戶的連接請求並通過調用accept函數接受客戶的連接請求。
3. 通過套接字進行網絡通訊
發送數據使用write、writev、send、 sendto 和sendmsg函數,其中前三個用於面向連接的數據發送,另外兩個用於無連接的數據發送。
接收數據使用read、 readv、 recv、 recvfrom和recvmsg,他們和上面的發送函數是一一對應的。
4. 關閉套接字,釋放Winsock資源
在通訊結束后,使用closesocket關閉不再使用的套接字並調用WSACleanup釋放底層的資源。