導航:首頁 > 編程系統 > linux套接字編程中的5個隱患

linux套接字編程中的5個隱患

發布時間:2023-08-15 22:41:39

㈠ 求助 linux c 編寫openssl socket套接字通信 運行時報錯 網路編程 不知道該怎麼辦啊

1.TCP流式套接字的編程步驟
在使用之前須鏈接庫函數:工程->設置->Link->輸入ws2_32.lib,OK!
SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);//創建套接字(socket)。

SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//轉換Unsigned short為網路位元組序的格式
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
客戶端代碼如下:
#include <Winsock2.h>
#include <stdio.h>

void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;

wVersionRequested = MAKEWORD( 1, 1 );

err = WSAStartup( wVersionRequested, &wsaData );載入套接字型檔
if ( err != 0 ) {
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup()( );
return;
}
SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);創建套接字(socket)。

SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));向伺服器發出連接請求(connect)。

char recvBuf[100];和伺服器端進行通信(send/recv)。
recv(sockClient,recvBuf,100,0);
printf("%s\n",recvBuf);
send(sockClient,"This is lisi",strlen("This is lisi")+1,0);

closesocket(sockClient);關閉套接字。
WSACleanup()();//必須調用這個函數清除參數
}

㈡ Linux 進程間套接字通信(Socket)基礎知識

姓名:羅學元    學號:21181214375    學院:廣州研究院

【嵌牛導讀】Linux進程間套接字通信基礎

【嵌牛鼻子】Linux 進程間套接字及通信介紹

【嵌牛提問】Linux進程間套接字包含哪些內容,如何實現通信

一、套接字(Socket)通信原理

套接字通信允許互聯的位於不同計算機上的進程之間實現通信功能。

二、套接字的屬性

套接字的特性由3個屬性確定,它們分別是:域、類型和協議。

1. 套接字的域

它指定套接字通信中使用的網路介質,最常見的套接字域是AF_INET,它指的是Internet網路。當客戶使用套接字進行跨網路的連接時,它就需要用到伺服器計算機的IP地址和埠來指定一台聯網機器上的某個特定服務,所以在使用socket作為通信的終點,伺服器應用程序必須在開始通信之前綁定一個埠,伺服器在指定的埠等待客戶的連接。

另一個域AF_UNIX表示UNIX文件系統,就是文件輸入/輸出,它的地址就是文件名。

2. 套接字類型

網際網路提供了兩種通信機制:流(stream)和數據報(datagram),因而套接字的類型也就分為流套接字和數據報套接字。我們主要看流套接字。

流套接字由類型SOCK_STREAM指定,它們是在AF_INET域中通過TCP/IP連接實現,同時也是AF_UNIX中常用的套接字類型。

流套接字提供的是一個有序、可靠、雙向位元組流的連接,因此發送的數據可以確保不會丟失、重復或亂序到達,而且它還有一定的出錯後重新發送的機制。

與流套接字相對的是由類型SOCK_DGRAM指定的數據報套接字,它不需要建立連接和維持一個連接,它們在AF_INET中通常是通過UDP/IP實現的。它對可以發送的數據的長度有限制,數據報作為一個單獨的網路消息被傳輸,它可能丟失、復制或錯亂到達,UDP不是一個可靠的協議,但是它的速度比較高,因為它並不需要總是要建立和維持一個連接。

3.套接字協議

只要底層的傳輸機制允許不止一個協議來提供要求的套接字類型,我們就可以為套接字選擇一個特定的協議。通常只需要使用默認值。

三、套接字地址

每個套接字都有其自己的地址格式,對於AF_UNIX域套接字來說,它的地址由結構sockaddr_un來描述,該結構定義在頭文件

struct sockaddr_un{

sa_family_t sun_family;  //AF_UNIX,它是一個短整型

char sum_path[];  //路徑名

};

對於AF_INET域套接字來說,它的地址結構由sockaddr_in來描述,它至少包括以下幾個成員:

struct sockaddr_in{

short int sin_family;  //AN_INET

unsigned short int sin_port;  //埠號

struct in_addr sin_addr;    //IP地址

}

而in_addr被定義為:

struct in_addr{

unsigned long int s_addr;

}

四、基於流套接字的客戶/伺服器的工作流程

使用socket進行進程通信的進程採用的客戶/伺服器系統是如何工作的呢?

1.伺服器端

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

接下來,伺服器進程會給套接字起個名字,我們使用系統調用bind來給套接字命名。然後伺服器進程就開始等待客戶連接到這個套接字。

然後,系統調用listen來創建一個隊列,並將其用於存放來自客戶的進入連接。

最後,伺服器通過系統調用accept來接受客戶的連接。它會創建一個與原有的命名套接不同的新套接字,這個套接字只用於與這個特定客戶端進行通信,而命名套接字(即原先的套接字)則被保留下來繼續處理來自其他客戶的連接。

2.客戶端

基於socket的客戶端比伺服器端簡單。同樣,客戶應用程序首先調用socket來創建一個未命名的套接字,然後講伺服器的命名套接字作為一個地址來調用connect與伺服器建立連接。

一旦連接建立,我們就可以像使用底層的文件描述符那樣用套接字來實現雙向數據的通信。

㈢ linux嵌套字的三種類型分別是什麼

阻塞和非阻塞
對於一個套接字的 I/O通信,它會涉及到兩個系統對象,一個是調用這個IO的進程或者線程,另一個就是系統內核。比如當一個讀操作發生時,它會經歷兩個階段:
①等待數據准備 (Waiting for the data to be ready)
②將數據從內核拷貝到進程中 (Copying the data from the kernel to the process)
阻塞,在Linux中,默認情況下所有的socket都是blocking,當用戶進程調用了recvfrom/recv這個系統調用,嚙合就開始了IO的第一個階段:准備數據。但是很多時候數據在一開始還沒有到達(比如,還沒有收到一個完整的UDP/TCP包),這個時候內核就要等待足夠的數據到來。而在用戶進程這邊,整個進程會被阻塞。當內核一直等到數據准備好了,它就會將數據從內核中拷貝到用戶內存,然後直到返回結果,用戶進程才解除阻塞的狀態,重新運行起來。
所以,阻塞IO的特點就是在IO執行的兩個階段都被阻塞了。
調用阻塞IO會一直阻塞對應的進程直到操作完成,而非阻塞IO在內核還准備數據的情況下會立刻返回。
阻塞
因此我們給出阻塞的簡單定義,阻塞調用是指調用結果返回之前,當前線程會被掛起(線程進入非可執行狀態,在這個狀態下,cpu不會給線程分配時間片,即線程暫停運行)。函數只有在得到結果之後才會返回。
有人也許會把阻塞調用和同步調用等同起來,實際上他是不同的。對於同步調用來說,很多時候當前線程還是激活的,只是從邏輯上當前函數沒有返回而已。 例如,我們在socket中調用recv函數,如果緩沖區中沒有數據,這個函數就會一直等待,直到有數據才返回。而此時,當前線程還會繼續處理各種各樣的消息,所以我們應該說我們的線程現在是阻塞的。
快遞的例子:比如到你某個時候到A樓一層(假如是內核緩沖區)取快遞,但是你不知道快遞什麼時候過來,你又不能幹別的事,只能死等著。但你可以睡覺(進程處於休眠狀態),因為你知道快遞把貨送來時一定會給你打個電話(假定一定能叫醒你)。
非阻塞
非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函數不會阻塞當前線程,而會立刻返回。
還是等快遞的例子:如果用忙輪詢的方法,每隔5分鍾到A樓一層(內核緩沖區)去看快遞來了沒有。如果沒來,立即返回。而快遞來了,就放在A樓一層,等你去取。
對象的阻塞模式和阻塞函數調用
對象是否處於阻塞模式和函數是不是阻塞調用有很強的相關性,但是並不是一一對應的。阻塞對象上可以有非阻塞的調用方式,我們可以通過一定的API去輪詢狀 態,在適當的時候調用阻塞函數,就可以避免阻塞。而對於非阻塞對象,調用特殊的函數也可以進入阻塞調用。我們經常使用的函數select就是這樣的一個例子。
同步與非同步
首先我們給出POSIX的定義
A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;
An asynchronous I/O operation does not cause the requesting process to be blocked; 1212

同步
用我們的話說,所謂同步,就是在發出一個功能調用時,在沒有得到結果之前,該調用就不返回。也就是必須一件一件事做,等前一件做完了才能做下一件事,而只有當所有的工作按照順序執行完之後,才會返回調用的位置,繼續往下執行。
這個很好理解,我們一般做的函數調用,都是同步的,我們的程序按照我們既定的順序一步一步執行,在前一個操作返回後,我們根據操作的結果,進行下一個階段的處理,這就是一個同步的過程。
非同步
非同步,非同步的概念和同步相對。當一個非同步過程調用發出後,調用者不能立刻得到結果。實際處理這個調用的部件在完成後,通過狀態、通知和回調來通知調用者。
簡單來說
一個同步接收的方式,在這個埠下如果同是來了兩個客戶端請求,第一個連接得到響應,與服務端建立通訊,而第二個請求就會被一直阻塞直到第一個請求完成操作,各個請求之間就好像排個隊,順序執行,這就是同步。
而一個非同步接收方式,就是同時來兩個或者多個請求,服務端就同時響應多個客戶端,同時給他們連接。各個客戶端與伺服器的通訊是並行的,一個客戶端不必等另一個客戶端完成操作。
兩者的區別就在於同步IO做IO操作的時候會將process阻塞
其實阻塞IO,非阻塞IO,以及我們後面會提到IO復用都屬於同步 IO。有人可能會說,非阻塞IO並沒有被阻塞啊。這里有個非常「狡猾」的地方,定義中所指的」IO operation」是指真實的IO操作,比如非阻塞IO在執行recvfrom這個系統調用的時候,如果內核的數據沒有準備好,這時候不會阻塞進程。但是,當內核中數據准備好的時候,recvfrom會將數據從內核拷貝到用戶內存中,在這段時間內,進程是被阻塞的。而非同步IO則不一樣,當進程發起IO 操作之後,就直接返回再也不理睬了,直到內核發送一個信號,告訴進程說IO完成。在這整個過程中,進程完全沒有被阻塞。
我們可以總結為一下幾點
同步 就是我調用一個功能,該功能沒有結束前,我死等結果。只能順序執行。
非同步 就是我調用一個功能,不需要知道該功能結果,該功能有結果後通知我(回調通知),往往用回調函數或者其他類方式實現。
阻塞 就是調用我(函數),我(函數)沒有接收完數據或者沒有得到結果之前,我不會返回。
非阻塞 就是調用我(函數),我(函數)立即返回,而當我准備完畢時,通過select通知調用者。
同步IO和非同步IO的區別就在於:數據拷貝的時候進程是否可以被阻塞
阻塞IO和非阻塞IO的區別就在於:應用程序的調用是否能立即返回
並發與迭代
套接字編程經常使用在客戶/伺服器編程模型(簡稱C/S模型)中,C/S模型根據復雜度分為簡單的客戶/伺服器模型和復雜的客戶/伺服器模型。
C/S簡單客戶/伺服器模型是一對一關系,一個伺服器端某一時間段內只對應處理一個客戶端的請求,迭代伺服器模型屬於此模型。
C/S復雜伺服器模型是一對多關系,一個伺服器端某一時間段內對應處理多個客戶端的請求,並發伺服器模型屬於此模型。
迭代伺服器模型和並發伺服器模型是socket編程中最常見使用的兩種編程模型。
通常來說大多數TCP伺服器是並發的,大多數UDP伺服器是迭代的
比如我們通常在做聊天室的時候,使用UDP協議來發送消息,但是在用戶需要上傳下載數據的時候,我們通常在伺服器和客戶端之間建立一個TCP連接來傳送文件。。。
但是如果服務一個客戶請求的時間不長,使用迭代伺服器沒有太大問題,一旦客戶請求的時間需要花費很長,不希望整個伺服器被單個客戶長期佔用,而希望同時服務多個客戶,就需要選擇並發伺服器了。

㈣ Linux C語言網路編程問題!

unsigned int dir(char * server) {
int sck;//套接字變數
struct sockaddr_in serv_adr; //遠程主機的地址
struct hostent *host; //指向遠程主機的指針
unsigned char databuf[FILEBUF_SIZE]; //數據
int bytes = 0, bytesread = 0; //位元組數,讀取到的位元組數

host = gethostbyname(server); //根據遠程主機的主機名,得到指向遠程主機的指針
if (host == (struct hostent *) NULL) { //如果得到指向遠程主機的指針失敗,報告錯誤,並返回
perror("gethostbyname failed");
return 0;
}memset(&serv_adr, 0, sizeof(serv_adr)); //初始化遠程主機的地址,結構體內所有成員清零
serv_adr.sin_family = AF_INET; //設置地址類型
memcpy(&serv_adr.sin_addr, host->h_addr, host->h_length);//取出指向遠程主機的指針中包含的地址信息,賦給遠程主機地址變數
serv_adr.sin_port = htons(SERVICE_PORT);//設置埠號,比如http服務對應80埠,ftp對應21埠

if ((sck = socket(AF_INET, SOCK_STREAM, 0)) < 0) { //如果建立TCP協議的套接字失敗,報告錯誤,並返回
perror("error on socket()");
return 0;
}
if (connect(sck, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) < 0) {//如果使用該套接字連接到遠程主機失敗,報告錯誤,並返回
perror("error on connect()");
return 0;
}write(sck, "DI\n\n", 4); //連接成功,發送內容為"DI\n\n"的消息,遠程主機收到該消息,解析後生成目錄列表,並將目錄列表信息傳遞回來
printf("Remote directory listing:\n");//輸出提示信息「遠程主機正在生成目錄列表」
while ((bytes = read(sck, databuf, FILEBUF_SIZE)) > 0) { //從套接字的數據流中讀取遠程主機的返回信息(即目錄列表),每次讀取FILEBUF_SIZE個位元組,直到全部讀取完畢
write(fileno(stdout), databuf, bytes);//將每次讀到的數據,輸出到標准輸出流(stdout),即屏幕
bytesread += bytes;//接收到的位元組數累加
}

close(sck); /* Close the socket */ //通信完成,關閉套接字,關閉連接

return bytesread; //返回讀取到的位元組數(即遠程主機返回的信息的大小)
}

㈤ 關於 Linux 網路,你必須知道這些

我們一起學習了文件系統和磁碟 I/O 的工作原理,以及相應的性能分析和優化方法。接下來,我們將進入下一個重要模塊—— Linux 的網路子系統。

由於網路處理的流程最復雜,跟我們前面講到的進程調度、中斷處理、內存管理以及 I/O 等都密不可分,所以,我把網路模塊作為最後一個資源模塊來講解。

同 CPU、內存以及 I/O 一樣,網路也是 Linux 系統最核心的功能。網路是一種把不同計算機或網路設備連接到一起的技術,它本質上是一種進程間通信方式,特別是跨系統的進程間通信,必須要通過網路才能進行。隨著高並發、分布式、雲計算、微服務等技術的普及,網路的性能也變得越來越重要。

說到網路,我想你肯定經常提起七層負載均衡、四層負載均衡,或者三層設備、二層設備等等。那麼,這里說的二層、三層、四層、七層又都是什麼意思呢?

實際上,這些層都來自國際標准化組織制定的開放式系統互聯通信參考模型(Open System Interconnection Reference Model),簡稱為 OSI 網路模型。

但是 OSI 模型還是太復雜了,也沒能提供一個可實現的方法。所以,在 Linux 中,我們實際上使用的是另一個更實用的四層模型,即 TCP/IP 網路模型。

TCP/IP 模型,把網路互聯的框架分為應用層、傳輸層、網路層、網路介面層等四層,其中,

為了幫你更形象理解 TCP/IP 與 OSI 模型的關系,我畫了一張圖,如下所示:

當然了,雖說 Linux 實際按照 TCP/IP 模型,實現了網路協議棧,但在平時的學習交流中,我們習慣上還是用 OSI 七層模型來描述。比如,說到七層和四層負載均衡,對應的分別是 OSI 模型中的應用層和傳輸層(而它們對應到 TCP/IP 模型中,實際上是四層和三層)。

OSI引入了服務、介面、協議、分層的概念,TCP/IP借鑒了OSI的這些概念建立TCP/IP模型。

OSI先有模型,後有協議,先有標准,後進行實踐;而TCP/IP則相反,先有協議和應用再提出了模型,且是參照的OSI模型。

OSI是一種理論下的模型,而TCP/IP已被廣泛使用,成為網路互聯事實上的標准。

有了 TCP/IP 模型後,在進行網路傳輸時,數據包就會按照協議棧,對上一層發來的數據進行逐層處理;然後封裝上該層的協議頭,再發送給下一層。

當然,網路包在每一層的處理邏輯,都取決於各層採用的網路協議。比如在應用層,一個提供 REST API 的應用,可以使用 HTTP 協議,把它需要傳輸的 JSON 數據封裝到 HTTP 協議中,然後向下傳遞給 TCP 層。

而封裝做的事情就很簡單了,只是在原來的負載前後,增加固定格式的元數據,原始的負載數據並不會被修改。

比如,以通過 TCP 協議通信的網路包為例,通過下面這張圖,我們可以看到,應用程序數據在每個層的封裝格式。

這些新增的頭部和尾部,增加了網路包的大小,但我們都知道,物理鏈路中並不能傳輸任意大小的數據包。網路介面配置的最大傳輸單元(MTU),就規定了最大的 IP 包大小。在我們最常用的乙太網中,MTU 默認值是 1500(這也是 Linux 的默認值)。

一旦網路包超過 MTU 的大小,就會在網路層分片,以保證分片後的 IP 包不大於 MTU 值。顯然,MTU 越大,需要的分包也就越少,自然,網路吞吐能力就越好。

理解了 TCP/IP 網路模型和網路包的封裝原理後,你很容易能想到,Linux 內核中的網路棧,其實也類似於 TCP/IP 的四層結構。如下圖所示,就是 Linux 通用 IP 網路棧的示意圖:

我們從上到下來看這個網路棧,你可以發現,

這里我簡單說一下網卡。網卡是發送和接收網路包的基本設備。在系統啟動過程中,網卡通過內核中的網卡驅動程序注冊到系統中。而在網路收發過程中,內核通過中斷跟網卡進行交互。

再結合前面提到的 Linux 網路棧,可以看出,網路包的處理非常復雜。所以,網卡硬中斷只處理最核心的網卡數據讀取或發送,而協議棧中的大部分邏輯,都會放到軟中斷中處理。

我們先來看網路包的接收流程。

當一個網路幀到達網卡後,網卡會通過 DMA 方式,把這個網路包放到收包隊列中;然後通過硬中斷,告訴中斷處理程序已經收到了網路包。

接著,網卡中斷處理程序會為網路幀分配內核數據結構(sk_buff),並將其拷貝到 sk_buff 緩沖區中;然後再通過軟中斷,通知內核收到了新的網路幀。

接下來,內核協議棧從緩沖區中取出網路幀,並通過網路協議棧,從下到上逐層處理這個網路幀。比如,

最後,應用程序就可以使用 Socket 介面,讀取到新接收到的數據了。

為了更清晰表示這個流程,我畫了一張圖,這張圖的左半部分表示接收流程,而圖中的粉色箭頭則表示網路包的處理路徑。

了解網路包的接收流程後,就很容易理解網路包的發送流程。網路包的發送流程就是上圖的右半部分,很容易發現,網路包的發送方向,正好跟接收方向相反。

首先,應用程序調用 Socket API(比如 sendmsg)發送網路包。

由於這是一個系統調用,所以會陷入到內核態的套接字層中。套接字層會把數據包放到 Socket 發送緩沖區中。

接下來,網路協議棧從 Socket 發送緩沖區中,取出數據包;再按照 TCP/IP 棧,從上到下逐層處理。比如,傳輸層和網路層,分別為其增加 TCP 頭和 IP 頭,執行路由查找確認下一跳的 IP,並按照 MTU 大小進行分片。

分片後的網路包,再送到網路介面層,進行物理地址定址,以找到下一跳的 MAC 地址。然後添加幀頭和幀尾,放到發包隊列中。這一切完成後,會有軟中斷通知驅動程序:發包隊列中有新的網路幀需要發送。

最後,驅動程序通過 DMA ,從發包隊列中讀出網路幀,並通過物理網卡把它發送出去。

多台伺服器通過網卡、交換機、路由器等網路設備連接到一起,構成了相互連接的網路。由於網路設備的異構性和網路協議的復雜性,國際標准化組織定義了一個七層的 OSI 網路模型,但是這個模型過於復雜,實際工作中的事實標准,是更為實用的 TCP/IP 模型。

TCP/IP 模型,把網路互聯的框架,分為應用層、傳輸層、網路層、網路介面層等四層,這也是 Linux 網路棧最核心的構成部分。

我結合網路上查閱的資料和文章中的內容,總結了下網卡收發報文的過程,不知道是否正確:

當發送數據包時,與上述相反。鏈路層將數據包封裝完畢後,放入網卡的DMA緩沖區,並調用系統硬中斷,通知網卡從緩沖區讀取並發送數據。

了解 Linux 網路的基本原理和收發流程後,你肯定迫不及待想知道,如何去觀察網路的性能情況。具體而言,哪些指標可以用來衡量 Linux 的網路性能呢?

實際上,我們通常用帶寬、吞吐量、延時、PPS(Packet Per Second)等指標衡量網路的性能。

除了這些指標,網路的可用性(網路能否正常通信)、並發連接數(TCP 連接數量)、丟包率(丟包百分比)、重傳率(重新傳輸的網路包比例)等也是常用的性能指標。

分析網路問題的第一步,通常是查看網路介面的配置和狀態。你可以使用 ifconfig 或者 ip 命令,來查看網路的配置。我個人更推薦使用 ip 工具,因為它提供了更豐富的功能和更易用的介面。

以網路介面 eth0 為例,你可以運行下面的兩個命令,查看它的配置和狀態:

你可以看到,ifconfig 和 ip 命令輸出的指標基本相同,只是顯示格式略微不同。比如,它們都包括了網路介面的狀態標志、MTU 大小、IP、子網、MAC 地址以及網路包收發的統計信息。

第一,網路介面的狀態標志。ifconfig 輸出中的 RUNNING ,或 ip 輸出中的 LOWER_UP ,都表示物理網路是連通的,即網卡已經連接到了交換機或者路由器中。如果你看不到它們,通常表示網線被拔掉了。

第二,MTU 的大小。MTU 默認大小是 1500,根據網路架構的不同(比如是否使用了 VXLAN 等疊加網路),你可能需要調大或者調小 MTU 的數值。

第三,網路介面的 IP 地址、子網以及 MAC 地址。這些都是保障網路功能正常工作所必需的,你需要確保配置正確。

第四,網路收發的位元組數、包數、錯誤數以及丟包情況,特別是 TX 和 RX 部分的 errors、dropped、overruns、carrier 以及 collisions 等指標不為 0 時,通常表示出現了網路 I/O 問題。其中:

ifconfig 和 ip 只顯示了網路介面收發數據包的統計信息,但在實際的性能問題中,網路協議棧中的統計信息,我們也必須關注。你可以用 netstat 或者 ss ,來查看套接字、網路棧、網路介面以及路由表的信息。

我個人更推薦,使用 ss 來查詢網路的連接信息,因為它比 netstat 提供了更好的性能(速度更快)。

比如,你可以執行下面的命令,查詢套接字信息:

netstat 和 ss 的輸出也是類似的,都展示了套接字的狀態、接收隊列、發送隊列、本地地址、遠端地址、進程 PID 和進程名稱等。

其中,接收隊列(Recv-Q)和發送隊列(Send-Q)需要你特別關注,它們通常應該是 0。當你發現它們不是 0 時,說明有網路包的堆積發生。當然還要注意,在不同套接字狀態下,它們的含義不同。

當套接字處於連接狀態(Established)時,

當套接字處於監聽狀態(Listening)時,

所謂全連接,是指伺服器收到了客戶端的 ACK,完成了 TCP 三次握手,然後就會把這個連接挪到全連接隊列中。這些全連接中的套接字,還需要被 accept() 系統調用取走,伺服器才可以開始真正處理客戶端的請求。

與全連接隊列相對應的,還有一個半連接隊列。所謂半連接是指還沒有完成 TCP 三次握手的連接,連接只進行了一半。伺服器收到了客戶端的 SYN 包後,就會把這個連接放到半連接隊列中,然後再向客戶端發送 SYN+ACK 包。

類似的,使用 netstat 或 ss ,也可以查看協議棧的信息:

這些協議棧的統計信息都很直觀。ss 只顯示已經連接、關閉、孤兒套接字等簡要統計,而 netstat 則提供的是更詳細的網路協議棧信息。

比如,上面 netstat 的輸出示例,就展示了 TCP 協議的主動連接、被動連接、失敗重試、發送和接收的分段數量等各種信息。

接下來,我們再來看看,如何查看系統當前的網路吞吐量和 PPS。在這里,我推薦使用我們的老朋友 sar,在前面的 CPU、內存和 I/O 模塊中,我們已經多次用到它。

給 sar 增加 -n 參數就可以查看網路的統計信息,比如網路介面(DEV)、網路介面錯誤(EDEV)、TCP、UDP、ICMP 等等。執行下面的命令,你就可以得到網路介面統計信息:

這兒輸出的指標比較多,我來簡單解釋下它們的含義。

其中,Bandwidth 可以用 ethtool 來查詢,它的單位通常是 Gb/s 或者 Mb/s,不過注意這里小寫字母 b ,表示比特而不是位元組。我們通常提到的千兆網卡、萬兆網卡等,單位也都是比特。如下你可以看到,我的 eth0 網卡就是一個千兆網卡:

其中,Bandwidth 可以用 ethtool 來查詢,它的單位通常是 Gb/s 或者 Mb/s,不過注意這里小寫字母 b ,表示比特而不是位元組。我們通常提到的千兆網卡、萬兆網卡等,單位也都是比特。如下你可以看到,我的 eth0 網卡就是一個千兆網卡:

我們通常使用帶寬、吞吐量、延時等指標,來衡量網路的性能;相應的,你可以用 ifconfig、netstat、ss、sar、ping 等工具,來查看這些網路的性能指標。

小狗同學問到: 老師,您好 ss —lntp 這個 當session處於listening中 rec-q 確定是 syn的backlog嗎?
A: Recv-Q為全連接隊列當前使用了多少。 中文資料里這個問題講得最明白的文章: https://mp.weixin.qq.com/s/yH3PzGEFopbpA-jw4MythQ

看了源碼發現,這個地方講的有問題.關於ss輸出中listen狀態套接字的Recv-Q表示全連接隊列當前使用了多少,也就是全連接隊列的當前長度,而Send-Q表示全連接隊列的最大長度

閱讀全文

與linux套接字編程中的5個隱患相關的資料

熱點內容
用數據說話是最有力的什麼 瀏覽:27
圖片文件被鎖定無法打開 瀏覽:768
wr886nv2升級 瀏覽:490
移動硬碟視頻文件無法刪除 瀏覽:417
如何查看網路監控 瀏覽:132
列印機如何連接到網路列印機 瀏覽:181
vmlinux安裝tools 瀏覽:768
波形文件轉mp3 瀏覽:803
linux查看網路 瀏覽:163
如何從cad軟體里列印命令文件 瀏覽:247
clover780ti黑蘋果 瀏覽:928
丙烷數據表哪裡有 瀏覽:72
一直生成photo文件夾 瀏覽:14
為什麼編程語言都是world 瀏覽:489
輕顏相機在手機里的哪個文件夾 瀏覽:547
王者什麼時候版本更新 瀏覽:123
win10桌面圖標太小亂跑 瀏覽:73
寫公文時保密數據如何反映 瀏覽:767
arch設置ip配置文件 瀏覽:641
燒杯APP中的氣體和液體在哪裡 瀏覽:3

友情鏈接