日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網營銷解決方案
LinuxTCP短鏈接技巧,提高網絡連接效率(linuxtcp短鏈接)

隨著互聯(lián)網應用的不斷發(fā)展,網絡通信技術已成為我們生活和工作中不可或缺的部分。為了提高網絡連接效率,Linux中常常通過一些技巧來實現TCP短鏈接。本文將介紹如何在Linux系統(tǒng)中實現TCP短鏈接,并提高網絡連接效率。

10多年的溫嶺網站建設經驗,針對設計、前端、開發(fā)、售后、文案、推廣等六對一服務,響應快,48小時及時工作處理。網絡營銷推廣的優(yōu)勢是能夠根據用戶設備顯示端的尺寸不同,自動調整溫嶺建站的顯示方式,使網站能夠適用不同顯示終端,在瀏覽器中調整網站的寬度,無論在任何一種瀏覽器上瀏覽網站,都能展現優(yōu)雅布局與設計,從而大程度地提升瀏覽體驗。成都創(chuàng)新互聯(lián)公司從事“溫嶺網站設計”,“溫嶺網站推廣”以來,每個客戶項目都認真落實執(zhí)行。

一、TCP半鏈接狀態(tài)

在介紹TCP短鏈接技巧之前,我們需要先了解一下TCP半鏈接狀態(tài)。當客戶端向服務器端發(fā)送SYN包時,服務器會回應一個SYN/ACK包,表示接受請求,并等待客戶端發(fā)送ACK包以確認建立連接。在這個過程中,服務器端會處于半鏈接狀態(tài),因為它已經接受了一個新的鏈接,但還沒有完全建立起來。

如果客戶端在接受到服務器端的SYN/ACK包前中止了連接,那么該半鏈接將留在服務器端,不能及時釋放,從而浪費服務器端資源。這種情況下,服務器會一直等到這個連接超時才會釋放,導致連接效率降低。因此,我們需要一些技巧來處理這種情況。

二、TCP Keepalive技巧

TCP Keepalive是一個用于檢測TCP連接是否活動的機制。當某個連接在一段時間內沒有活動,Keepalive機制會發(fā)送一些特殊的探測包來檢查連接是否仍然存在。如果連接已經中斷,那么服務器將及時釋放資源,從而提高連接效率。

在Linux中,可以通過以下命令設置TCP Keepalive機制:

“`

# 命令格式

echo seconds > /proc/sys/net/ipv4/tcp_keepalive_time

echo tries > /proc/sys/net/ipv4/tcp_keepalive_probes

echo seconds > /proc/sys/net/ipv4/tcp_keepalive_intvl

# 參數解釋

# seconds:表示開始發(fā)送TCP Keepalive包的時間間隔(單位為秒),默認為7200秒(2小時)。

# tries:表示在發(fā)送之一個TCP Keepalive包前嘗試多少次發(fā)送數據包,默認為9次。

# seconds:表示在發(fā)送TCP Keepalive包后多長時間發(fā)送下一個包(單位為秒),默認為75秒。

“`

通過設置TCP Keepalive機制,可以讓服務器端及時釋放TCP半鏈接狀態(tài),從而提高網絡連接效率。

三、TCP Fastopen技巧

TCP Fastopen是一種新的TCP協(xié)議擴展,它可以在之一次握手時傳送數據,從而避免建立鏈接的延遲。在TCP Fastopen機制下,服務器端可以在之一次握手時向客戶端發(fā)送一些數據,而不需要等待客戶端發(fā)送ACK包。

在Linux中,可以通過以下命令開啟TCP Fastopen機制:

“`

# 命令格式

sysctl -w net.ipv4.tcp_fastopen=1

“`

啟用TCP Fastopen機制后,可以通過一些技巧來利用它提高網絡連接效率。例如,可以將網站的靜態(tài)資源(例如圖片、CSS、JavaScript等)放在一個單獨的域名下,然后將該域名的TCP Fastopen機制開啟,從而加速加載速度。

四、TCP Time_wt優(yōu)化技巧

TCP Time_wt是一個用于保持連接狀態(tài)的機制,它確保當連接中的最后一個數據包丟失時服務器不會立即釋放連接,從而避免數據包丟失。然而,如果連接量過大,Time_wt機制會占用服務器端的大量資源,從而使連接效率降低。

在Linux中,可以通過以下技巧來優(yōu)化TCP Time_wt機制:

(1)調整Time_wt狀態(tài)的更大數量

通過調整Time_wt狀態(tài)的更大數量,可以控制服務器端的資源占用情況。在Linux中,可以通過以下命令調整Time_wt狀態(tài)的更大數量:

“`

# 命令格式

echo value > /proc/sys/net/ipv4/tcp_max_tw_buckets

# 參數解釋

# value:表示更大的Time_wt狀態(tài)數量,默認為180000。

“`

(2)開啟TCP Long Time_wt

TCP Long Time_wt是一種可以延長Time_wt狀態(tài)的機制,它可以在超時時間為2倍的MSL(Maximum Segment Lifetime,更大報文壽命)時關閉TCP連接。在Linux中,可以通過以下命令開啟TCP Long Time_wt機制:

“`

# 命令格式

echo seconds > /proc/sys/net/ipv4/tcp_tw_reuse

# 參數解釋

# seconds:表示最長的TCP Long Time_wt時間,默認為0。

“`

通過以上技巧,可以優(yōu)化TCP Time_wt機制,從而提高網絡連接效率。

五、

通過以上介紹,我們可以了解Linux中如何實現TCP短鏈接技巧,從而提高網絡連接效率。通過采用TCP Keepalive、TCP Fastopen和TCP Time_wt優(yōu)化技巧,可以讓服務器端及時釋放TCP半鏈接狀態(tài),避免TCP連接過程中的延遲,提高網絡連接效率,為互聯(lián)網應用的發(fā)展提供更好的支持。

相關問題拓展閱讀:

  • 如何看懂《Linux多線程服務端編程

如何看懂《Linux多線程服務端編程

一:進程和線程

每個進程有自己獨立的地址空間?!霸谕粋€進程”還是“不在同一個進程”是系統(tǒng)功能劃分的重要決策點?!禘rlang程序設計》把進程比喻為人:

每個人有自己的記憶(內存),人與人通過談話(消息傳遞)來交流,談話既可以是面談姿并野(同一臺服務器),也可以在里談(不同的服務器,有網絡通信)。面談和談的區(qū)別在于,面談可以立即知道對方是否死了(crash,SIGCHLD),而談只能通過周期性的心跳來判斷對方是否還活著。

有了這些比喻,設計分布式系統(tǒng)時可以采取“角色扮演”,團隊里的幾個人各自扮演一個進程,人的角色由進程的代碼決定(管登錄的、管消息分發(fā)的、管買賣的等等)。每個人有自己的記憶,但不知道別人的記憶,要想知道別人的看法,只能通過交談(暫不考慮共享內存這種IPC)。然后就可以思考:跡喊

·容錯:萬一有人突然死了

·擴容:新人中途加進來

·負載均衡:把甲的活兒挪給乙做

·退休:甲要修復bug,先別派新任務,等他做完手上的事情就把他重啟

等等各種場景,十分便利。

線程的特點是共享地址空間,從而可以高效地共享數據。一臺機器上的多個進程能高效地共享代碼段(操作系統(tǒng)可以映射為同樣的物理內存),但不能共享數據。如果多個進程大量共享內存,等于是把多進程程序當成多線程來寫,掩耳盜鈴。

“多線程”的價值,我認為是為了更好地發(fā)揮多核處理器(multi-cores)的效能。在單核時代,多線程沒有多大價值(個人想法:如果要完成的任務是CPU密集型的,那多線程沒有優(yōu)勢,甚至因為線程切換的開銷,多線程反而更慢;如果要完成的任務既有CPU計算,又有磁盤或網絡IO,則使用多線程的好處是,當某個線程因為IO而阻塞時,OS可以調度其他線程執(zhí)行,雖然效率確實要比任務的順序執(zhí)行效率要高,然而,這種類型的任務,可以通過單線程的”non-blocking IO+IO multiplexing”的模型(事件驅動)來提高效率,采用多線程的方式,帶來的可能僅僅是編程上的簡單而已)。Alan Cox說過:”A computer is a state machine.Threads are for people who can’t program state machines.”(計算機是一臺狀態(tài)機。線程是給那些不能編寫狀態(tài)機程序的人準備的)如果只有一塊CPU、一個執(zhí)行單元,那么確實如Alan Cox所說,按狀態(tài)機的思路去寫程序是最蔽謹高效的。

二:單線程服務器的常用編程模型

據我了解,在高性能的網絡程序中,使用得最為廣泛的恐怕要數”non-blocking IO + IO multiplexing”這種模型,即Reactor模式。

在”non-blocking IO + IO multiplexing”這種模型中,程序的基本結構是一個事件循環(huán)(event loop),以事件驅動(event-driven)和事件回調的方式實現業(yè)務邏輯:

view plain copy

//代碼僅為示意,沒有完整考慮各種情況

while(!done)

{

int timeout_ms = max(1000, getNextTimedCallback());

int retval = poll(fds, nfds, timeout_ms);

if (retval0){

處理IO事件,回調用戶的IO event handler

}

}

}

這里select(2)/poll(2)有伸縮性方面的不足(描述符過多時,效率較低),Linux下可替換為epoll(4),其他操作系統(tǒng)也有對應的高性能替代品。

Reactor模型的優(yōu)點很明顯,編程不難,效率也不錯。不僅可以用于讀寫socket,連接的建立(connect(2)/accept(2)),甚至DNS解析都可以用非阻塞方式進行,以提高并發(fā)度和吞吐量(throughput),對于IO密集的應用是個不錯的選擇。lighttpd就是這樣,它內部的fdevent結構十分精妙,值得學習。

基于事件驅動的編程模型也有其本質的缺點,它要求事件回調函數必須是非阻塞的。對于涉及網絡IO的請求響應式協(xié)議,它容易割裂業(yè)務邏輯,使其散布于多個回調函數之中,相對不容易理解和維護。

三:多線程服務器的常用編程模型

大概有這么幾種:

a:每個請求創(chuàng)建一個線程,使用阻塞式IO操作。在Java 1.4引人NIO之前,這是Java網絡編程的推薦做法。可惜伸縮性不佳(請求太多時,操作系統(tǒng)創(chuàng)建不了這許多線程)。

b:使用線程池,同樣使用阻塞式IO操作。與第1種相比,這是提高性能的措施。

c:使用non-blocking IO + IO multiplexing。即Java NIO的方式。

d:Leader/Follower等高級模式。

在默認情況下,我會使用第3種,即non-blocking IO + one loop per thread模式來編寫多線程C++網絡服務程序。

1:one loop per thread

此種模型下,程序里的每個IO線程有一個event loop,用于處理讀寫和定時事件(無論周期性的還是單次的)。代碼框架跟“單線程服務器的常用編程模型”一節(jié)中的一樣。

libev的作者說:

One loop per thread is usually a good model. Doing this is almost never wrong, some times a better-performance model exists, but it is always a good start.

這種方式的好處是:

a:線程數目基本固定,可以在程序啟動的時候設置,不會頻繁創(chuàng)建與銷毀。

b:可以很方便地在線程間調配負載。

c:IO事件發(fā)生的線程是固定的,同一個TCP連接不必考慮事件并發(fā)。

Event loop代表了線程的主循環(huán),需要讓哪個線程干活,就把timer或IO channel(如TCP連接)注冊到哪個線程的loop里即可:對實時性有要求的connection可以單獨用一個線程;數據量大的connection可以獨占一個線程,并把數據處理任務分攤到另幾個計算線程中(用線程池);其他次要的輔助性connections可以共享一個線程。

比如,在dbproxy中,一個線程用于專門處理客戶端發(fā)來的管理命令;一個線程用于處理客戶端發(fā)來的MySQL命令,而與后端數據庫通信執(zhí)行該命令時,是將該任務分配給所有事件線程處理的。

對于non-trivial(有一定規(guī)模)的服務端程序,一般會采用non-blocking IO + IO multiplexing,每個connection/acceptor都會注冊到某個event loop上,程序里有多個event loop,每個線程至多有一個event loop。

多線程程序對event loop提出了更高的要求,那就是“線程安全”。要允許一個線程往別的線程的loop里塞東西,這個loop必須得是線程安全的。

在dbproxy中,線程向其他線程分發(fā)任務,是通過管道和隊列實現的。比如主線程accept到連接后,將表示該連接的結構放入隊列,并向管道中寫入一個字節(jié)。計算線程在自己的event loop中注冊管道的讀事件,一旦有數據可讀,就嘗試從隊列中取任務。

2:線程池

不過,對于沒有IO而光有計算任務的線程,使用event loop有點浪費。可以使用一種補充方案,即用blocking queue實現的任務隊列:

view plain copy

typedef boost::functionFunctor;

BlockingQueue taskQueue; //線程安全的全局阻塞隊列

//計算線程

void workerThread()

{

while (running) //running變量是個全局標志

{

Functor task = taskQueue.take(); //this blocks

task(); //在產品代碼中需要考慮異常處理

}

}

// 創(chuàng)建容量(并發(fā)數)為N的線程池

int N = num_of_computing_threads;

for (int i = 0; i

{

create_thread(&workerThread); //啟動線程

}

//向任務隊列中追加任務

Foo foo; //Foo有calc()成員函數

boost::function task = boost::bind(&Foo::calc,&foo);

taskQueue.post(task);

除了任務隊列,還可以用BlockingQueue實現數據的生產者消費者隊列,即T是數據類型而非函數對象,queue的消費者從中拿到數據進行處理。其實本質上是一樣的。

3:總結

總結而言,我推薦的C++多線程服務端編程模式為:one (event) loop per thread + thread pool:

event loop用作IO multiplexing,配合non-blockingIO和定時器;

thread pool用來做計算,具體可以是任務隊列或生產者消費者隊列。

以這種方式寫服務器程序,需要一個優(yōu)質的基于Reactor模式的網絡庫來支撐,muduo正是這樣的網絡庫。比如dbproxy使用的是libevent。

程序里具體用幾個loop、線程池的大小等參數需要根據應用來設定,基本的原則是“阻抗匹配”(解釋見下),使得CPU和IO都能高效地運作。所謂阻抗匹配原則:

如果池中線程在執(zhí)行任務時,密集計算所占的時間比重為 P (0

以后我再講這個經驗公式是怎么來的,先驗證邊界條件的正確性。

假設 C = 8,P = 1.0,線程池的任務完全是密集計算,那么T = 8。只要 8 個活動線程就能讓 8 個 CPU 飽和,再多也沒用,因為 CPU 資源已經耗光了。

假設 C = 8,P = 0.5,線程池的任務有一半是計算,有一半等在 IO 上,那么T = 16??紤]操作系統(tǒng)能靈活合理地調度 sleeping/writing/running 線程,那么大概 16 個“50%繁忙的線程”能讓 8 個 CPU 忙個不停。啟動更多的線程并不能提高吞吐量,反而因為增加上下文切換的開銷而降低性能。

如果 P

另外,公式里的 C 不一定是 CPU 總數,可以是“分配給這項任務的 CPU 數目”,比如在 8 核機器上分出 4 個核來做一項任務,那么 C=4。

四:進程間通信只用TCP

Linux下進程間通信的方式有:匿名管道(pipe)、具名管道(FIFO)、POSIX消息隊列、共享內存、信號(signals),以及Socket。同步原語有互斥器(mutex)、條件變量(condition variable)、讀寫鎖(reader-writer lock)、文件鎖(record locking)、信號量(semaphore)等等。

進程間通信我首選Sockets(主要指TCP,我沒有用過UDP,也不考慮Unix domain協(xié)議)。其好處在于:

可以跨主機,具有伸縮性。反正都是多進程了,如果一臺機器的處理能力不夠,很自然地就能用多臺機器來處理。把進程分散到同一局域網的多臺機器上,程序改改host:port配置就能繼續(xù)用;

TCP sockets和pipe都是操作文件描述符,用來收發(fā)字節(jié)流,都可以read/write/fcntl/select/poll等。不同的是,TCP是雙向的,Linux的pipe是單向的,進程間雙向通信還得開兩個文件描述符,不方便;而且進程要有父子關系才能用pipe,這些都限制了pipe的使用;

TCP port由一個進程獨占,且進程退出時操作系統(tǒng)會自動回收文件描述符。因此即使程序意外退出,也不會給系統(tǒng)留下垃圾,程序重啟之后能比較容易地恢復,而不需要重啟操作系統(tǒng)(用跨進程的mutex就有這個風險);而且,port是獨占的,可以防止程序重復啟動,后面那個進程搶不到port,自然就沒法初始化了,避免造成意料之外的結果;

與其他IPC相比,TCP協(xié)議的一個天生的好處是“可記錄、可重現”。tcpdump和Wireshark是解決兩個進程間協(xié)議和狀態(tài)爭端的好幫手,也是性能(吞吐量、延遲)分析的利器。我們可以借此編寫分布式程序的自動化回歸測試。也可以用tcpcopy之類的工具進行壓力測試。TCP還能跨語言,服務端和客戶端不必使用同一種語言。

分布式系統(tǒng)的軟件設計和功能劃分一般應該以“進程”為單位。從宏觀上看,一個分布式系統(tǒng)是由運行在多臺機器上的多個進程組成的,進程之間采用TCP長連接通信。

使用TCP長連接的好處有兩點:一是容易定位分布式系統(tǒng)中的服務之間的依賴關系。只要在機器上運行netstat -tpna|grep 就能立刻列出用到某服務的客戶端地址(Foreign Address列),然后在客戶端的機器上用netstat或lsof命令找出是哪個進程發(fā)起的連接。TCP短連接和UDP則不具備這一特性。二是通過接收和發(fā)送隊列的長度也較容易定位網絡或程序故障。在正常運行的時候,netstat打印的Recv-Q和Send-Q都應該接近0,或者在0附近擺動。如果Recv-Q保持不變或持續(xù)增加,則通常意味著服務進程的處理速度變慢,可能發(fā)生了死鎖或阻塞。如果Send-Q保持不變或持續(xù)增加,有可能是對方服務器太忙、來不及處理,也有可能是網絡中間某個路由器或交換機故障造成丟包,甚至對方服務器掉線,這些因素都可能表現為數據發(fā)送不出去。通過持續(xù)監(jiān)控Recv-Q和Send-Q就能及早預警性能或可用性故障。以下是服務端線程阻塞造成Recv-Q和客戶端Send-Q激增的例子:

view plain copy

$netstat -tn

Proto Recv-Q Send-Q Local Address Foreign

tcp.0.0.10:.0.0.10:39748 #服務端連接

tcp.0.0.10:.0.0.10:2023 #客戶端連接

tcp.0.0.10:22 10.0.0.4:55572

五:多線程服務器的適用場合

如果要在一臺多核機器上提供一種服務或執(zhí)行一個任務,可用的模式有:

a:運行一個單線程的進程;

b:運行一個多線程的進程;

c:運行多個單線程的進程;

d:運行多個多線程的進程;

考慮這樣的場景:如果使用速率為50MB/s的數據壓縮庫,進程創(chuàng)建銷毀的開銷是800微秒,線程創(chuàng)建銷毀的開銷是50微秒。如何執(zhí)行壓縮任務?

如果要偶爾壓縮1GB的文本文件,預計運行時間是20s,那么起一個進程去做是合理的,因為進程啟動和銷毀的開銷遠遠小于實際任務的耗時。

如果要經常壓縮500kB的文本數據,預計運行時間是10ms,那么每次都起進程 似乎有點浪費了,可以每次單獨起一個線程去做。

如果要頻繁壓縮10kB的文本數據,預計運行時間是200微秒,那么每次起線程似 乎也很浪費,不如直接在當前線程搞定。也可以用一個線程池,每次把壓縮任務交給線程池,避免阻塞當前線程(特別要避免阻塞IO線程)。

由此可見,多線程并不是萬靈丹(silver bullet)。

1:必須使用單線程的場合

據我所知,有兩種場合必須使用單線程:

a:程序可能會fork(2);

實際編程中,應該保證只有單線程程序能進行fork(2)。多線程程序不是不能調用fork(2),而是這么做會遇到很多麻煩:

fork一般不能在多線程程序中調用,因為Linux的fork只克隆當前線程的thread of control,不可隆其他線程。fork之后,除了當前線程之外,其他線程都消失了。

這就造成一種危險的局面。其他線程可能正好處于臨界區(qū)之內,持有了某個鎖,而它突然死亡,再也沒有機會去解鎖了。此時如果子進程試圖再對同一個mutex加鎖,就會立即死鎖。因此,fork之后,子進程就相當于處于signal handler之中(因為不知道調用fork時,父進程中的線程此時正在調用什么函數,這和信號發(fā)生時的場景一樣),你不能調用線程安全的函數(除非它是可重入的),而只能調用異步信號安全的函數。比如,fork之后,子進程不能調用:

malloc,因為malloc在訪問全局狀態(tài)時幾乎肯定會加鎖;

任何可能分配或釋放內存的函數,比如snprintf;

任何Pthreads函數;

printf系列函數,因為其他線程可能恰好持有stdout/stderr的鎖;

除了man 7 signal中明確列出的信號安全函數之外的任何函數。

因此,多線程中調用fork,唯一安全的做法是fork之后,立即調用exec執(zhí)行另一個程序,徹底隔斷子進程與父進程的聯(lián)系。

在多線程環(huán)境中調用fork,產生子進程后。子進程內部只存在一個線程,也就是父進程中調用fork的線程的副本。

使用fork創(chuàng)建子進程時,子進程通過繼承整個地址空間的副本,也從父進程那里繼承了所有互斥量、讀寫鎖和條件變量的狀態(tài)。如果父進程中的某個線程占有鎖,則子進程同樣占有這些鎖。問題是子進程并不包含占有鎖的線程的副本,所以子進程沒有辦法知道它占有了哪些鎖,并且需要釋放哪些鎖。

盡管Pthread提供了pthread_atfork函數試圖繞過這樣的問題,但是這回使得代碼變得混亂。因此《Programming With Posix Threads》一書的作者說:”Avoid using fork in threaded code except where the child process will immediately exec a new program.”。

b:限制程序的CPU占用率;

這個很容易理解,比如在一個8核的服務器上,一個單線程程序即便發(fā)生busy-wait,占滿1個core,其CPU使用率也只有12.5%,在這種最壞的情況下,系統(tǒng)還是有87.5%的計算資源可供其他服務進程使用。

linux tcp短鏈接的介紹就聊到這里吧,感謝你花時間閱讀本站內容,更多關于linux tcp短鏈接,Linux TCP短鏈接技巧,提高網絡連接效率,如何看懂《Linux多線程服務端編程的信息別忘了在本站進行查找喔。

香港服務器選創(chuàng)新互聯(lián),2H2G首月10元開通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網服務提供商,擁有超過10年的服務器租用、服務器托管、云服務器、虛擬主機、網站系統(tǒng)開發(fā)經驗。專業(yè)提供云主機、虛擬主機、域名注冊、VPS主機、云服務器、香港云服務器、免備案服務器等。


網站標題:LinuxTCP短鏈接技巧,提高網絡連接效率(linuxtcp短鏈接)
當前網址:http://www.dlmjj.cn/article/djhjosj.html