1. 程式人生 > >socket套接字詳解

socket套接字詳解

  套接字是一種通訊機制(通訊的兩方的一種約定),憑藉這種機制,不同主機之間的程序可以進行通訊。我們可以用套接字中的相關函式來完成通訊過程

  套接字的特性有三個屬性確定,它們是:域(domain),型別(type),和協議(protocol)。

#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain, int type, int protocol);

一、域(domain)

  域指定套接字通訊中使用的網路介質。最常見的套接字域是 AF_INET(IPv4)或者AF_INET6(IPV6)

,它是指 Internet 網路,許多 Linux 區域網使用的都是該網路,當然,因特網自身用的也是它。

二、型別(type)

  • 流套接字(SOCK_STREAM):

  流套接字用於提供面向連線、可靠的資料傳輸服務。該服務將保證資料能夠實現無差錯、無重複傳送,並按順序接收。流套接字之所以能夠實現可靠的資料服務,原因在於其使用了傳輸控制協議,即TCP(The Transmission Control Protocol)協議。

  • 資料報套接字(SOCK_DGRAM):

  資料報套接字提供了一種無連線的服務。該服務並不能保證資料傳輸的可靠性,資料有可能在傳輸過程中丟失或出現數據重複,且無法保證順序地接收到資料。資料報套接字使用UDP(User Datagram Protocol)協議進行資料的傳輸。由於資料報套接字不能保證資料傳輸的可靠性,對於有可能出現的資料丟失情況,需要在程式中做相應的處理。

  • 原始套接字(SOCK_RAW):

  原始套接字與標準套接字(標準套接字指的是前面介紹的流套接字和資料報套接字)的區別在於:原始套接字可以讀寫核心沒有處理的IP資料包,而流套接字只能讀取TCP協議的資料,資料報套接字只能讀取UDP協議的資料。因此,如果要訪問其他協議傳送資料必須使用原始套接字

三、協議(protocol)

  • 0:

   使用預設協議;

  • IPPROTO_TCP;

   使用TCP協議;

  • IPPROTO_UDP;

   使用UDP協議;

四、socket緩衝區以及阻塞模式

1、緩衝區簡介

  每個 socket 被建立後,都會分配兩個緩衝區,輸入緩衝區和輸出緩衝區。

  write()/send() 並不立即向網路中傳輸資料,而是先將資料寫入緩衝區中,再由TCP協議將資料從緩衝區傳送到目標機器。一旦將資料寫入到緩衝區,函式就可以成功返回,不管它們有沒有到達目標機器,也不管它們何時被髮送到網路,這些都是TCP協議負責的事情。   read()/recv() 函式也是如此,也從輸入緩衝區中讀取資料,而不是直接從網路中讀取。 在這裡插入圖片描述

  • I/O緩衝區在每個TCP套接字中單獨存在;
  • I/O緩衝區在建立套接字時自動生成;
  • 即使關閉套接字也會繼續傳送輸出緩衝區中遺留的資料;
  • 關閉套接字將丟失輸入緩衝區中的資料。

2、阻塞模式

【對於TCP套接字(預設情況下),當使用 write()/send() 傳送資料時】:

1. 首先會檢查緩衝區,如果緩衝區的可用空間長度小於要傳送的資料,那麼 write()/send() 會被阻塞(暫停執行),直到緩衝區中的資料被髮送到目標機器,騰出足夠的空間,才喚醒 write()/send() 函式繼續寫入資料;

2. 如果TCP協議正在向網路傳送資料,那麼輸出緩衝區會被鎖定,不允許寫入,write()/send() 也會被阻塞,直到資料傳送完畢緩衝區解鎖,write()/send() 才會被喚醒。如果TCP協議正在向網路傳送資料,那麼輸出緩衝區會被鎖定,不允許寫入,write()/send() 也會被阻塞,直到資料傳送完畢緩衝區解鎖,write()/send() 才會被喚醒;

3. 如果要寫入的資料大於緩衝區的最大長度,那麼將分批寫入。如果要寫入的資料大於緩衝區的最大長度,那麼將分批寫入;

4. 直到所有資料被寫入緩衝區 write()/send() 才能返回。直到所有資料被寫入緩衝區 write()/send() 才能返回。

【當使用 read()/recv() 讀取資料時】:

1. 首先會檢查緩衝區,如果緩衝區中有資料,那麼就讀取,否則函式會被阻塞,直到網路上有資料到來

2. 如果要讀取的資料長度小於緩衝區中的資料長度,那麼就不能一次性將緩衝區中的所有資料讀出,剩餘資料將不斷積壓,直到有 read()/recv() 函式再次讀取。如果要讀取的資料長度小於緩衝區中的資料長度,那麼就不能一次性將緩衝區中的所有資料讀出,剩餘資料將不斷積壓,直到有 read()/recv() 函式再次讀取;

3. 直到讀取到資料後 read()/recv() 函式才會返回,否則就一直被阻塞。