1. 程式人生 > >效能測試-socket協議

效能測試-socket協議

測試過程中,你一定遇到不少網路通訊的情況,最常見的如網路語音通訊、文字傳輸、微信QQ聊天、瀏覽器訪問等等,這些都涉及到網路程序間通訊,然而這些程序間是如何通訊的呢?你一定聽開發同學提過很多次socket這個東西,沒錯,一切都是靠Socket實現的。它為何如此神奇?下面小編做個科普,幫你揭開Socket的神祕面紗~

  1. 網路程序間通訊
    要了解Socket首先要熟悉網路程序通訊的原理,一個完整的網路應用程式包括客戶端和伺服器兩個部分。網路間通訊需要由兩個程序組成,並且只能用同一種協議,也就是說,不能在通訊的一端使用TCP協議,而另一端則用UDP協議。
    在TCP/IP協議中,兩個因特網主機通過兩個路由器和對應的層連線。各主機上的應用通過一些資料通道相互執行讀取操作,如下圖所示:

實現網路間通訊,要解決一個首要問題是-如何唯一標識一個程序,在網路上,通常利用ip地址+協議+埠號唯一標示網路中的一個程序。IP層的ip地址可以唯一標示主機,而TCP層協議和埠號可以唯一標示主機的一個程序,這樣它們就可以利用Socket進行通訊了。
2. Socket套接字
網路中的程序是通過Socket來通訊的,那麼Socket是什麼呢?Socket是一個程序間通訊終結點,它是Socket應用程式用來在網路上傳送或接收資料包的物件,是應用層與TCP/IP協議族通訊的中間軟體抽象層,它是一組介面。
如下圖所示,在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket介面後面,對使用者來說,一組簡單的介面就是全部,讓Socket去組織資料,以符合指定的協議。

 Socket的使用型別主要有兩種:
(1)流套接字(streamsocket):基於 TCP協議,採用流的方式提供可靠的位元組流服務;
(2)資料報套接字(datagramsocket):基於 UDP協議,採用資料報文提供資料打包傳送的服務。
  1. Socket通訊流程
    Socket起源於UNIX,在Unix一切皆檔案哲學的思想下,Socket是一種"開啟—讀/寫—關閉"模式的實現,伺服器和客戶端各自維護一個"檔案",在建立連線開啟後,可以向自己檔案寫入內容供對方讀取或者讀取對方內容,通訊結束時關閉檔案。以使用TCP協議通訊的Socket為例,其互動流程大概是這樣子的:

(1)伺服器根據地址型別(ipv4,ipv6)、socket型別、協議建立socket;
(2)伺服器為socket繫結ip地址和埠號;
(3)伺服器socket監聽埠號請求,隨時準備接收客戶端發來的連線,這時候伺服器的socket並沒有被開啟;
(4)客戶端建立socket;
(5)客戶端開啟socket,根據伺服器ip地址和埠號試圖連線伺服器socket;
(6)伺服器socket接收到客戶端socket請求,被動開啟,開始接收客戶端請求,直到客戶端返回連線資訊。這時候socket進入阻塞狀態,所謂阻塞即accept()方法一直到客戶端返回連線資訊後才返回,開始接收下一個客戶端諒解請求;
(7)客戶端連線成功,向伺服器傳送連線狀態資訊;
(8)伺服器accept方法返回,連線成功;
(9)客戶端向socket寫入資訊;
(10)伺服器讀取資訊;
(11)客戶端關閉;
(12)伺服器端關閉。
以上,一次socket通訊流程的互動結束。
4. 程式碼實現
(1)建立一個socket:socket()
int socket(int domain, int type, int protocol);

  • domain:與socket通訊的domain。
  • type:socket型別,SOCK_STREAM(TCP),SOCK_DGRAM(UDP)。
  • protocol:通常指定為0,在RAW_SOCKET中為IPPROTO_RAW。
    return: 新建立socket的檔案描述符。
    (2)將socket繫結到地址:bind()
    int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
  • sockfd:在socket()呼叫取得的檔案描述符。
  • addr:要socket繫結到的地址。
  • addrlen:制定了地址結構的大小。
    return:-1為繫結失敗。
    (3)監聽接入連線:listen()
    int listen(int sockfd, int backlog);
  • sockfd:socket檔案描述符。
  • backlog:限制未決連線的數量(在呼叫accept()前收到connect()的連線)。
    return: -1為監聽失敗。
    (4)接受連線:accept()
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • sockfd:socket檔案描述符。
  • addr:對端socket的地址結構。
  • addrlen:對端socket地址結構的長度。
    return:和對端連線的檔案描述符。
    當呼叫accept()時,會建立一個新的socket,並且由這個新建立的socket來與執行connect()的對等socket進行連線。
    (5)連線到對等socket:connect()
    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd:socket檔案描述符。
  • addr:要連線到socket的地址。
  • addrlen:地址結構的長度。
    (6)連線終止:close()
    終止一個流socket的連線,如果多個檔案描述符引用了一個socket,那麼所有描述符被關閉後才會終止(若呼叫shutdown()則可以強制關閉socket上的通道)。
  1. Socket中TCP的三次握手建立連線詳解
    TCP建立連線要進行“三次握手”,即交換三個分組。大致流程如下:
    1)客戶端向伺服器傳送一個SYN J;
    2)伺服器向客戶端響應一個SYN K,並對SYN J進行確認ACKJ+1;
    3)客戶端再想伺服器發一個確認ACK K+1。

當客戶端呼叫connect時,觸發了連線請求,向伺服器傳送了SYN J包,這時connect進入阻塞狀態;伺服器監聽到連線請求,即收到SYN J包,呼叫accept函式接收請求向客戶端傳送SYN K ,ACK J+1,這時accept進入阻塞狀態;客戶端收到伺服器的SYN K ,ACK J+1之後,這時connect返回,並對SYN K進行確認;伺服器收到ACK K+1時,accept返回,至此三次握手完畢,連線建立。
6. Socket中TCP的四次握手釋放連線
Socket中四次握手釋放連線的過程,請看下圖:
大致流程為:
1)某個應用程序首先呼叫close主動關閉連線,這時TCP傳送一個FIN M;
2)另一端接收到FIN M之後,執行被動關閉,對這個FIN進行確認。它的接收也作為檔案結束符傳遞給應用程序,因為FIN的接收意味著應用程序在相應的連線上再也接收不到額外資料;
3)一段時間之後,接收到檔案結束符的應用程序呼叫close關閉它的Socket。這導致它的TCP也傳送一個FIN N;
4)接收到這個FIN的源傳送端TCP對它進行確認。