基於TCP協議的socket編程

一、什麼是socket

socket本身有“插座”的意思,在TCP/IP協議中,“IP地址+TCP或UDP端口號”唯一標識網絡通訊中的個進程,“IP地址+端口號”就稱爲socket。  

在TCP協議中,建立連接的兩個進程各自有一個socket來標識,那麼這兩個socket組成 的socketpair就唯一標識一個連接。

套接字是一種進程間的通信的方法,不同於以往介紹的進程間通信方法的是,它並不侷限於同一臺計算機的資源,例如文件系統空間,共享內存或者消息隊列。套接字可以認爲是對管道概念的擴展——一臺機器上的進程可以使用套接字與另一臺機器上的進程通信。因此客戶與服務器可以分散在網絡中。同一臺機器上的進程間也可以用套接字通信。套接字是一種通信機制,客戶/服務器系統既可以在本地單機上運行,也可以在網絡中運行。套接字與管道的區別:它明確區分客戶與服務器,可以實現將多個客戶連接到一個服務器。


二、1.網絡字節序:

我們已經知道,內存中的多字節數據相對於內存地址有大端和小端之分,磁盤文件中的多字節數據相對於

文件中的偏移地址也有大端小端之分。網絡數據流同樣有大端小端之分,發送主機通常將發送緩衝區中的數據按內存地址從低到高的順序發出,接收主機把從網絡上接到的字節依次保存在接收緩衝區中,也是按內存地址從低到高的順序保存,因此,網絡數據流的地址應這樣規定:先發出的數據是低地址,後發出的數據是高地址。TCP/IP協議規定,絡數據流應採用大端字節序,即低地址高字節。例如UDP段格式中地址0-1是16位的源端口號,如果這個端口號是1000(0x3e8),則地址0是0x03,地址1是0xe8, 也就是先發0x03,再發0xe8,這16位在發送主機的緩衝區中也應該是低地址存0x03,高地址存0xe8。但是,如果發送主機是小端字節序的,這16位被解釋成0xe803,而不是1000。因此,發送主機把1000填到發送緩衝區之前需要做字節序的轉換。同樣地,接收主機如果是小端字節序的, 接到16位的源端口號也要做字節序的轉換。如果主機是大端字節序的,發送和接收都不需要做轉換。同理,32位的IP地址也要考慮網絡字節序和主機字節序的問題。爲使絡程序具有可移植性,使同樣的C代碼在大端和小端計算機上編譯後都能正常運,可以調 用以下庫函數做網絡字節序和主機字節序的轉換。

wKiom1dET9qhoewKAAA0xa82wp0775.jpg


h表示host,n表示network,l表示32位長整數,s表示16位短整數。例 如htonl表示將32位的長整數從主機字節序轉換爲網絡字節序,例如將IP地址轉換後準備發送。如果 主機是小端字節序,這些函數將參數做相應的大小端轉換然後返回,如果主機是大端字節序,這些函數不做轉換,將參數原封不動地返回。

2.socket地址的數據類型及相關函數

socket API是層抽象的網絡編程接,適用於各種底層網絡協議,如IPv4、IPv6,以及UNIX Domain Socket。然而,各種網絡協議的地址格式並不相同,在這裏我們使用sockaddr_in;

wKioL1dEUOqRR27LAABe5pDxq7g384.jpg


3.基於IPv4的socket網絡編程,sockaddr_in中的成員struct in_addr sin_addr表示32位的IP地址。但是我們通常用點分十進制的字符串表示IP 地址,以下函數可以在字符串表示 和in_addr表示之間轉換。 

字符串轉in_addr的函數:  

wKioL1dEUQzBZC7eAAAn2vPSip8626.jpg

in_addr轉字符串的函數:

wKiom1dEUBmDyFBTAAAZsgi3X7I362.jpg

 

4.套接字的工作過程(服務器端):

首先,服務器應用程序通過socket系統調用創建一個套接字,它是系統分配給該服務器進程的類似文件描述符的資源,不能與其他進程共享。

wKiom1dEUYGj9WdYAAAU9DGMcLk550.jpg

成功則返回一個文件描述符,失敗返回-1;


其次,服務器進程使用bind系統調用給套接字命名。本地套接字的名字是linux文件系統的文件名,一般放在/tmp或者/usr/tmp 目錄下。網絡套接字的名字是與客戶相連接的特定網絡有關的服務標識符。此標識符允許linux將進入的針對特定端口號的連接轉到正確的服務器進程。

wKioL1dEUq-inmMSAAAUpS3GKmE792.jpg

成功返回0,失敗返回-1;


接下來,服務器進程開始等待客戶連接到這個命名套接字,調用listen創建一個等待隊列以便存放來自客戶的進入連接。

wKioL1dEUtDAdF9qAAALB7xBSQM595.jpg

同樣成功返回0,失敗返回-1


最後,服務器通過accept系統調用來接受客戶的連接。此時,會產生一個與原有的命名套接字不同的新套接字,它僅用於與這個特定的客戶通信,而命名套接字則被保留下來繼續處理來自其他客戶的連接。

  wKioL1dEU2yCoJUJAAAmIwkjg6c173.jpg

失敗則返回-1;


    5.套接字的工作過程客戶端):調用socket創建一個未命名套接字,將服務器的命名套接字作爲一個地址來調用connect與服務器建立連接。一旦建立了連接,就可以像使用底層文件描述符那樣來用套接字進行雙向的數據通信。

三、如下例子

sever端:

wKiom1dEVvuxT_-RAADOXy5wwVk047.jpg

wKioL1dEV_CBXOacAACT7IS64Z8451.jpg

wKiom1dEVv7CtQkPAACUOBnETu0322.jpg

wKioL1dEV_KitmvcAACiIswelbE170.jpg

wKioL1dEV_OjpOAeAACRs0GPTp8973.jpg

client端:

wKiom1dEVwDSopzGAACuRCE05K4103.jpg

wKioL1dEV_ThC8emAABzeJWLH08015.jpg

運行結果:

其中左邊爲sever端,右邊爲client端:例子中的V1,V2,V3是針對單進程,多進程,多線程的。

wKiom1dEVwGhaOqqAAA1Rafnui8270.jpg




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章