1. 程式人生 > >linux網路程式設計TCP_DEFER_ACCEPT

linux網路程式設計TCP_DEFER_ACCEPT

原文連結:http://blog.csdn.net/hbhhww/article/details/8237309

我們首先考慮的第1個選項是TCP_DEFER_ACCEPT(這是Linux系統上的叫法,其他一些作業系統上也有同樣的選項但使用不同的名字)。為了理解TCP_DEFER_ACCEPT選項的具體思想,我們有必要大致闡述一下典型的HTTP客戶/伺服器互動過程。請回想下TCP是如何與傳輸資料的目標建立連線的。在網路上,在分離的單元之間傳輸的資訊稱為IP包(或IP 資料報)。一個包總有一個攜帶服務資訊的包頭,包頭用於內部協議的處理,並且它也可以攜帶資料負載。服務資訊的典型例子就是一套所謂的標誌,它把包標記代表TCP/IP協議

棧內的特殊含義,例如收到包的成功確認等等。通常,在經過“標記”的包裡攜帶負載是完全可能的,但有時,內部邏輯迫使TCP/IP協議棧發出只有包頭的IP包。這些包經常會引發討厭的網路延遲而且還增加了系統的負載,結果導致網路效能在整體上降低。

  現在伺服器建立了一個套接字同時等待連線。TCP/IP式的連線過程就是所謂“3次握手”。首先,客戶程式傳送一個設定SYN標誌而且不帶資料負載的TCP包(一個SYN包)。伺服器則以發出帶SYN/ACK標誌的資料包(一個SYN/ACK包)作為剛才收到包的確認響應。客戶隨後傳送一個ACK包確認收到了第2個包從而結束連線過程。在收到客戶發來的這個ACK包之後,伺服器會喚醒一個接收程序等待資料到達。當3次握手完成後,客戶程式即開始把“有用的”的資料傳送給伺服器。通常,一個HTTP請求的量是很小的而且完全可以裝到一個包裡。但是,在以上的情況下,至少有4個包將用來進行雙向傳輸,這樣就增加了可觀的延遲時間。此外,你還得注意到,在“有用的”資料被髮送之前,接收方已經開始在等待資訊了。

  為了減輕這些問題所帶來的影響,Linux(以及其他的一些作業系統)在其TCP實現中包括了TCP_DEFER_ACCEPT選項。它們設定在偵聽套接字的伺服器方,該選項命令核心不等待最後的ACK包而且在第1個真正有資料的包到達才初始化偵聽程序。在傳送SYN/ACK包之後,伺服器就會等待客戶程式傳送含資料的IP包。現在,只需要在網路上傳送3個包了,而且還顯著降低了連線建立的延遲,對HTTP通訊而言尤其如此。這一選項在好些作業系統上都有相應的對等物。例如,在FreeBSD上,同樣的行為可以用以下程式碼實現:

  /* 為明晰起見,此處略去無關程式碼 */

  struct accept_filter_arg af = { "dataready", "" };

  setsockopt(s, SOL_SOCKET, SO_ACCEPTFILTER, &af, sizeof(af));

  這個特徵在FreeBSD上叫做“接受過濾器”,而且具有多種用法。不過,在幾乎所有的情況下其效果與TCP_DEFER_ACCEPT是一樣的:伺服器不等待最後的ACK包而僅僅等待攜帶資料負載的包。要了解該選項及其對高效能Web伺服器的重要意義的更多資訊請參考Apache文件上的有關內容。

  就HTTP客戶/伺服器互動而言,有可能需要改變客戶程式的行為。客戶程式為什麼要傳送這種“無用的”ACK包呢?這是因為,TCP協議棧無法知道ACK包的狀態。如果採用FTP而非HTTP,那麼客戶程式直到接收了FTP伺服器提示的資料包之後才傳送資料。在這種情況下,延遲的ACK將導致客戶/伺服器互動出現延遲。為了確定ACK是否必要,客戶程式必須知道應用程式協議及其當前狀態。這樣,修改客戶行為就成為必要了。

  對Linux客戶程式來說,我們還可以採用另一個選項,它也被叫做TCP_DEFER_ACCEPT。我們知道,套接字分成兩種型別,偵聽套接字和連線套接字,所以它們也各自具有相應的TCP選項集合。因此,經常同時採用的這兩類選項卻具有同樣的名字也是完全可能的。在連線套接字上設定該選項以後,客戶在收到一個

  SYN/ACK包之後就不再發送ACK包,而是等待使用者程式的下一個傳送資料請求;因此,伺服器傳送的包也就相應減少了。

tcp三次握手過程:

第一次握手:建立連線時,客戶端傳送syn包(syn=j)到伺服器,並進入SYN_SEND狀態,等待伺服器確認; 

第二次握手:伺服器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也傳送一個SYN包(syn=k),即SYN+ACK包,此時伺服器進入SYN_RECV狀態; 

第三次握手:客戶端收到伺服器的SYN+ACK包,向伺服器傳送確認包ACK(ack=k+1),此包傳送完畢,客戶端和伺服器進入ESTABLISHED狀態,完成三次握手。

伺服器在三次握手後會喚起一個程序等待資料到達,當伺服器設定了TCP_DEFER_ACCEPT後,核心不等待最後一個ACK包,而且在第一個真正有資料的包到達後才初始化偵聽過程,可以減少一些上下文切換,三次握手後,如果沒有資料到來,伺服器socket處於SYN_RECV狀態,這個時候就依賴於net.ipv4.tcp_synack_retries引數控制了,當達到重傳後,過指定的時間關閉socket

看測試程式

伺服器環境:Linux version 2.6 + gcc,ip:192.168.30.202

客戶端環境:win32 + vs2010,ip:192.168.30.12

沒有設定TCP_DEFER_ACCEPT,三次握手的抓包:

[[email protected] ~]# tcpdump tcp port 10000

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes

16:30:59.486716 IP 192.168.30.12.4326 > 192.168.30.202.ndmp: S 1992149464:1992149464(0) win 65535 <mss 1460,nop,nop,sackOK>

16:30:59.490951 IP 192.168.30.202.ndmp > 192.168.30.12.4326: S 524361898:524361898(0) ack 1992149465 win 5840 <mss 1460,nop,nop,sackOK>

16:30:59.491059 IP 192.168.30.12.4326 > 192.168.30.202.ndmp: . ack 1 win 65535

設定TCP_DEFER_ACCEPT,通過命令“sysctl -w net.ipv4.tcp_synack_retries=1”設定重傳後,抓包如下:

[[email protected] ~]# tcpdump tcp port 10000

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes

16:35:12.764157 IP 192.168.30.12.4548 > 192.168.30.202.ndmp: S 1431219651:1431219651(0) win 65535 <mss 1460,nop,nop,sackOK>

16:35:12.767924 IP 192.168.30.202.ndmp > 192.168.30.12.4548: S 795485424:795485424(0) ack 1431219652 win 5840 <mss 1460,nop,nop,sackOK>

16:35:12.768044 IP 192.168.30.12.4548 > 192.168.30.202.ndmp: . ack 1 win 65535

16:35:15.726875 IP 192.168.30.202.ndmp > 192.168.30.12.4548: S 795485424:795485424(0) ack 1431219652 win 5840 <mss 1460,nop,nop,sackOK>

16:35:15.726980 IP 192.168.30.12.4548 > 192.168.30.202.ndmp: . ack 1 win 65535

設定TCP_DEFER_ACCEPT,通過命令“sysctl -w net.ipv4.tcp_synack_retries=3”設定重傳後,抓包如下:

[[email protected] ~]# tcpdump tcp port 10000

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes

16:36:57.993105 IP 192.168.30.12.4648 > 192.168.30.202.ndmp: S 242062800:242062800(0) win 65535 <mss 1460,nop,nop,sackOK>

16:36:57.996526 IP 192.168.30.202.ndmp > 192.168.30.12.4648: S 917726329:917726329(0) ack 242062801 win 5840 <mss 1460,nop,nop,sackOK>

16:36:57.996567 IP 192.168.30.12.4648 > 192.168.30.202.ndmp: . ack 1 win 65535

16:37:02.140832 IP 192.168.30.202.ndmp > 192.168.30.12.4648: S 917726329:917726329(0) ack 242062801 win 5840 <mss 1460,nop,nop,sackOK>

16:37:02.141226 IP 192.168.30.12.4648 > 192.168.30.202.ndmp: . ack 1 win 65535

16:37:08.065966 IP 192.168.30.202.ndmp > 192.168.30.12.4648: S 917726329:917726329(0) ack 242062801 win 5840 <mss 1460,nop,nop,sackOK>

16:37:08.066190 IP 192.168.30.12.4648 > 192.168.30.202.ndmp: . ack 1 win 65535

16:37:19.915745 IP 192.168.30.202.ndmp > 192.168.30.12.4648: S 917726329:917726329(0) ack 242062801 win 5840 <mss 1460,nop,nop,sackOK>

16:37:19.915993 IP 192.168.30.12.4648 > 192.168.30.202.ndmp: . ack 1 win 65535

上面抓包結果可以看出結果,不過還有個問題沒弄明白,當達到重傳次數後,過指定的時間關閉socket,這個時間沒有準確的計算出來

int val = 10;

if (setsockopt(sock_descriptor, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val))== -1)

{

perror("setsockopt");

exit(1);

}

val以秒為單位,val設定的時間越久,測試出這個等待關閉的時間就越久,具體沒弄清楚是多少,或者是由其他什麼控制的,杯具啊!!

相關推薦

linux網路程式設計TCP_DEFER_ACCEPT

原文連結:http://blog.csdn.net/hbhhww/article/details/8237309 我們首先考慮的第1個選項是TCP_DEFER_ACCEPT(這是Linux系統上的叫法,其他一些作業系統上也有同樣的選項但使用不同的名字)。為了理解TCP_

Linux網路程式設計:TCP客戶/伺服器模型及基本socket函式

TCP客戶/伺服器模型 TCP連線的分組交換 在使用socket API的時候應該清楚應用程式和TCP協議棧是如何互動的: 呼叫connect()會發出SYN段(SYN是TCP報文段頭部的一個標誌位,置為1) 阻塞的read()函式返回0就表明收到了FIN段 客戶端呼叫c

Linux網路程式設計:socket程式設計簡介、網路位元組序及相關函式

Socket(套接字) socket可以看成是使用者程序與核心網路協議棧的程式設計介面(API函式)。 socket不僅可以用於本機的程序間通訊,還可以用於網路上不同主機的程序間通訊。 IPv4套接字地址結構 IPv4套接字地址結構通常也稱為“網際套接字地址結構”,它以

Linux網路程式設計案例分析

本程式碼來自於博主:輝夜星辰  本篇主要對執行程式碼中出現的問題進行分析,程式碼本身的內容後續展開討論。 伺服器端程式碼 1 /* 2 Linux網路程式設計之TCP程式設計,伺服器端讀資料 3 socket函式之後,返回值serfd,作為後面所有網路程式設計函式

Linux網路程式設計---深刻理解5種基本IO模型

Linux五種IO模型 理解這五種I/O模型之前,我們得先清楚一個IO事件發生,它會經歷哪些步驟: 對於一個網路IO(network IO) (這裡我們以read舉例),它會涉及到兩個系統物件,一個是呼叫這個IO的process (or thread),另一個就是系統核心(kerne

Linux網路程式設計---詳解TCP的三次握手和四次揮手

我們知道,在TCP/IP協議中,TCP協議提供可靠的連線服務,是因為它有許多保證可靠連線的機制。可以分為3個方面: 1.確認應答機制:指的是不管哪一端傳送資料都需要確認回覆一下。 2.超時重傳機制,傳送後等待一段時間,不管是傳送失敗或者是還沒有收到回覆,那麼就認為資料傳輸失敗了;此時將會

Linux網路程式設計---I/O多路複用之select

1.I/O多路複用(IO multiplexing) 我們之前講了I/O多路複用和其他I/O的區別,在這裡,我們再具體討論下I/O多路複用是怎麼工作? I/O 多路複用技術就是為了解決程序或執行緒阻塞到某個 I/O 系統呼叫而出現的技術,使程序不阻塞於某個特定的 I/O 系統呼叫。

Linux網路程式設計---詳解HTTP協議

HTTP 簡介 HTTP協議是Hyper Text Transfer Protocol(超文字傳輸協議)的縮寫,是用於從全球資訊網(WWW:World Wide Web )伺服器傳輸超文字到本地瀏覽器的傳送協議。。 HTTP是一個基於TCP/IP通訊協議來傳遞資料(HTML 檔案,

linux 網路程式設計之廣播

linux 網路程式設計之廣播 轉載:https://blog.csdn.net/qdlovecsj/article/details/8805483 廣播方式主要是指使用UDP套介面傳送資料,傳送資料的目標地址不是普通的地址,而是所指定網路的廣播地址。 什麼是廣播地址?是指IP地

Linux網路程式設計入門 (轉載)

https://www.cnblogs.com/duzouzhe/archive/2009/06/19/1506699.html#3448454 (一)Linux網路程式設計--網路知識介紹 Linux網路程式設計--網路知識介紹 客戶端和服務端    &nbs

Linux網路程式設計入門

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Linux網路程式設計之TCP程式設計

直接上程式碼如下所示: 1、標頭檔案定義 #ifndef __HEAD_NET_H__ #define __HEAD_NET_H__ #include <stdio.h> #include <string.h> #include <stdlib.h>

Linux網路程式設計---解決TIME_WAIT狀態引起的bind失敗的方法

好幾天都沒寫部落格了,感覺落後了別人一大截,今天趕緊來補補。廢話不多說,直接進入正題。 首先我們得明白,有些情況下,在server的TCP連線沒有完全斷開之前是不允許重新監聽可能是不合理的 例如: 伺服器需要處理非常大量的客戶端的連線(每個連線的生存時間可能很短, 但是每

Linux 網路程式設計——內網和外網之間的通訊流程

對於初學者而已,我們學習的網路程式設計(如TCP,UDP程式設計),我們通常都是在區域網內進行通訊測試,有時候我們或者會想,我們現在寫的內網網路資料和外網的網路資料有什麼不同,我們內網的資料是如何走出外網的呢? 再者,我們大多人都是使用寬頻上網,結果發現,A 和 B 的區域網 IP 都是192.

Linux 網路程式設計—— libnet庫詳細使用指南

概述 通過《原始套接字例項:傳送 UDP 資料包》的學習,我們組 UDP 資料包時常考慮位元組流順序、校驗和計算等問題,有時候會比較繁瑣,那麼,有沒有一種更簡單的方法呢?答案是:藉助 libnet 函式庫。 libnet 是一個小型的介面函式庫,主要用 C 語言寫成,提供了低層網路資料

Linux網路程式設計之IO模型

本文基於IO訪問中存在的兩個階段詳細介紹了Linux產生的五種IO模型。 上篇文章回顧: 小米開源監控Open-Falcon收錄汽車之家貢獻的Win版Agent 同步與非同步 同步是指一個任務的完成需要依賴另外一個任務時,只有等待被依賴的任務完成後

linux網路程式設計之多程序併發伺服器

1)使用多程序併發伺服器考慮的因素:       (1)父程序描述最大檔案描述符的個數(父程序需要關閉accept返回的新檔案描述符)       (2)系統內可建立程序的個數(與記憶體大小相關)       (3)程序建立過多是否降低整體服務效能 2)多程序建立併發

linux網路程式設計之TCP狀態轉換及埠複用

(1)TCP狀態轉換圖               其中圖中分為三種狀態:實線代表的主動發起連線,虛線代表的被動發起連線,細實線代表的可以雙向發起連線的狀態。 主動發起連線方狀態變化:1)主動發起連線的一方傳送SYN標誌位,進入SYN_SENT狀態,等待接收被髮起連線方

Linux 網路程式設計 全解(一)--------網路基礎協議

寫在前面:說一下寫這個系列的目的,隨著對網路開發的深入,越來越覺得自己網路基礎知識的薄弱,雖然開發過程中不需要對網路基礎有很深入的瞭解照樣能進行,但有一些問題仍然是不知其因,所以這個系列打算從最基本的網路知識展開記錄,也是一邊學習一邊整理筆記。歡迎大家共同學習,QQ:9936

Linux 網路程式設計 全解(三)--------TCP三次握手、資料傳輸、四次揮手、滑動視窗

寫在前面:今天中秋佳節,首先祝大家佳節快樂,身體健康,恭喜發財。吃也吃了,喝也喝了,玩也玩了,乾點正事吧。 說一下寫這個系列的目的,隨著對物聯網開發的深入,越來越覺得自己網路基礎知識的薄弱,雖然開發過程中不需要對網路基礎有很深入的瞭解照樣能進行,但有一些問題仍然是不知其因,