TCP accept返回的socket,服務端TCP鏈接數限制

http://www.cppblog.com/aa19870406/archive/2012/07/15/183595.html

socket accept()返回的socket描述符的端口和listen描述符端口是同樣的嗎?

as you know,一個socket是由一個五元組來惟一標示的,即(協議,server_ip, server_port, client_ip, client_port)。只要該五元組中任何一個值不一樣,則其表明的socket就不一樣。這裏忽略協議的區別,在同一協議的基礎上,服務器端的listen socket的端口能夠當作(server_ip, server_port, ***, ***),其中***是通配符,它跟任何一個client_ip, client_port值都不一樣,能夠簡單當作是(0,0)對,固然實現不是這樣的。這樣在服務器端accept以後,返回的鏈接socket的四元組就是(server_ip, server_port, client_ip, client_port),這裏的client_ip,client_port因鏈接的客戶端的不一樣而不一樣。因此accept返回的socket和listen socket是不一樣的,不一樣之處就在於四元組中的客戶端ip和port,而服務器端的server_ip和server_port仍是相同的,也就是accpet()函數返回的新的socket描述符的端口和listen端口是同樣的。可使用getsockname()函數來查看它們之間的不一樣。html

 

http://blog.csdn.net/hanzengyi/article/details/5365029程序員

 

accept是又產生一個Socket端口嗎?面試

      要寫網絡程序就必須用Socket,這是程序員都知道的。並且,面試的時候,咱們也會問對方會不會Socket編程?通常來講,不少人都會說,Socket編程基本就是listen,accept以及send,write等幾個基本的操做。是的,就跟常見的文件操做同樣,只要寫過就必定知道。編程

 

      對於網絡編程,咱們也言必稱TCP/IP,彷佛其它網絡協議已經不存在了。對於TCP/IP,咱們還知道TCP和UDP,前者能夠保證數據的正確和可靠性,後者則容許數據丟失。最後,咱們還知道,在創建鏈接前,必須知道對方的IP地址和端口號。除此,普通的程序員就不會知道太多了,不少時候這些知識已經夠用了。最多,寫服務程序的時候,會使用多線程來處理併發訪問。windows

 

咱們還知道以下幾個事實:緩存

     1.一個指定的端口號不能被多個程序共用。好比,若是IIS佔用了80端口,那麼Apache就不能也用80端口了。服務器

     2.不少防火牆只容許特定目標端口的數據包經過。網絡

     3.服務程序在listen某個端口並accept某個鏈接請求後,會生成一個新的socket來對該請求進行處理。多線程

 

     因而,一個困惑了我好久的問題就產生了。若是一個socket建立後並與80端口綁定後,是否就意味着該socket佔用了80端口呢?若是是這樣的,那麼當其accept一個請求後,生成的新的socket到底使用的是什麼端口呢(我一直覺得系統會默認給其分配一個空閒的端口號)?若是是一個空閒的端口,那必定不是80端口了,因而之後的TCP數據包的目標端口就不是80了--防火牆必定會阻止其經過的!實際上,咱們能夠看到,防火牆並無阻止這樣的鏈接,並且這是最多見的鏈接請求和處理方式。個人不解就是,爲何防火牆沒有阻止這樣的鏈接?它是如何斷定那條鏈接是由於connet80端口而生成的?是否是TCP數據包裏有什麼特別的標誌?或者防火牆記住了什麼東西?併發

 

      後來,我又仔細研讀了TCP/IP的協議棧的原理,對不少概念有了更深入的認識。好比,在TCP和UDP同屬於傳輸層,共同架設在IP層(網絡層)之上。而IP層主要負責的是在節點之間(End to End)的數據包傳送,這裏的節點是一臺網絡設備,好比計算機。由於IP層只負責把數據送到節點,而不能區分上面的不一樣應用,因此TCP和UDP協議在其基礎上加入了端口的信息,端口因而標識的是一個節點上的一個應用。除了增長端口信息,UPD協議基本就沒有對IP層的數據進行任何的處理了。而TCP協議還加入了更加複雜的傳輸控制,好比滑動的數據發送窗口(Slice Window),以及接收確認和重發機制,以達到數據的可靠傳送。無論應用層看到的是怎樣一個穩定的TCP數據流,下面傳送的都是一個個的IP數據包,須要由TCP協議來進行數據重組。

 

      因此,我有理由懷疑,防火牆並無足夠的信息判斷TCP數據包的更多信息,除了IP地址和端口號。並且,咱們也看到,所謂的端口,是爲了區分不一樣的應用的,以在不一樣的IP包來到的時候可以正確轉發。

 

     TCP/IP只是一個協議棧,就像操做系統的運行機制同樣,必需要具體實現,同時還要提供對外的操做接口。就像操做系統會提供標準的編程接口,好比Win32編程接口同樣,TCP/IP也必須對外提供編程接口,這就是Socket編程接口--原來是這麼回事啊!

 

在Socket編程接口裏,設計者提出了一個很重要的概念,那就是socket。這個socket跟文件句柄很類似,實際上在BSD系統裏就是跟文件句柄同樣存放在同樣的進程句柄表裏。這個socket實際上是一個序號,表示其在句柄表中的位置。這一點,咱們已經見過不少了,好比文件句柄,窗口句柄等等。這些句柄,實際上是表明了系統中的某些特定的對象,用於在各類函數中做爲參數傳入,以對特定的對象進行操做--這實際上是C語言的問題,在C++語言裏,這個句柄其實就是this指針,實際就是對象指針啦。

 

如今咱們知道,socket跟TCP/IP並無必然的聯繫。Socket編程接口在設計的時候,就但願也能適應其餘的網絡協議。因此,socket的出現只是能夠更方便的使用TCP/IP協議棧而已,其對TCP/IP進行了抽象,造成了幾個最基本的函數接口。好比create,listen,accept,connect,read和write等等。

 

如今咱們明白,若是一個程序建立了一個socket,並讓其監聽80端口,實際上是向TCP/IP協議棧聲明瞭其對80端口的佔有。之後,全部目標是80端口的TCP數據包都會轉發給該程序(這裏的程序,由於使用的是Socket編程接口,因此首先由Socket層來處理)。所謂accept函數,其實抽象的是TCP的鏈接創建過程。accept函數返回的新socket其實指代的是本次建立的鏈接,而一個鏈接是包括兩部分信息的,一個是源IP和源端口,另外一個是宿IP和宿端口。因此,accept能夠產生多個不一樣的socket,而這些socket裏包含的宿IP和宿端口是不變的,變化的只是源IP和源端口。這樣的話,這些socket宿端口就能夠都是80,而Socket層仍是能根據源/宿對來準確地分辨出IP包和socket的歸屬關係,從而完成對TCP/IP協議的操做封裝!而同時,放火牆的對IP包的處理規則也是清晰明瞭,不存在前面設想的種種複雜的情形。

 

明白socket只是對TCP/IP協議棧操做的抽象,而不是簡單的映射關係,這很重要!

 

http://blog.csdn.net/zztfj/article/details/10103621http://blog.csdn.net/zztfj/article/details/10103621

 

 單機最大的TCP鏈接數及其修改
一個誤解: 單個服務器程序可承受最大鏈接數「理論」上是「65535」 .

   65535這個數字的由來,不少人想固然地將它與port最大值聯繫起來。的確,TCP的端口數,最大值確實爲65535。可是,這並不表明一個服務器能夠接受的鏈接數就是這個值。不少人之因此把這兩個概念搞混淆是由於對socket和port沒有更深的認識和理解。咱們先來回想一下服務器服務的前後過程:
一、服務器建立監聽socket
二、與對外服務的端口號綁定
三、開始listen
四、客戶端鏈接到服務器對應的port
五、服務器accept爲新的客戶端產生新的socket
六、基於這個新的socket與客戶端交換數據。
從以上流程來看,最大值爲65535的「端口號」這個重要的東東,咱們只用了一次,就是執行bind的時候!而之後建立的socket,說白了就是一個能夠進行網絡IO操做的HANDLE而已。經過查看該HANDLE的RemoteEndPoint能查看到遠程客戶端鏈接的IP和端口號(注意,該端口是遠程客戶端的端口),查看該HANDLE的LocalEndPoint能看到該Socket的Ip和端口就是該服務綁定的IP和端口。因此,accept的socket值與端口號無關,又何來65535的「理論」上限?

好了,已經弄明白了服務器端接收的客戶端鏈接鏈接數不受最大端口號65535的限制。可是,在客戶端,應用程序最多能夠創建多少個TCP鏈接呢?以及如何調整系統參數來調整單機的最大TCP鏈接數。

Windows 下單機的TCP鏈接數有多個參數共同決定,下面一一介紹:

最大TCP鏈接數
[HKEY_LOCAL_MACHINE \System \CurrentControlSet \Services \Tcpip \Parameters]
TcpNumConnections = 0x00fffffe (Default = 16,777,214)

 

以上註冊表信息配置單機的最大容許的TCP鏈接數,默認爲 16M。這個數值看似很大,這個並非限制最大鏈接數的惟一條件,還有其餘條件會限制到TCP 鏈接的最大鏈接數。

最大動態端口數
TCP客戶端和服務器鏈接時,客戶端必須分配一個動態端口,默認狀況下這個動態端口的分配範圍爲 1024-5000 ,也就是說默認狀況下,客戶端最多能夠同時發起3977 個Socket 鏈接。咱們能夠修改以下注冊表來調整這個動態端口的範圍

[HKEY_LOCAL_MACHINE \System \CurrentControlSet \Services \Tcpip \Parameters]
MaxUserPort = 5000 (Default = 5000, Max = 65534)

 

最大TCB 數量
系統爲每一個TCP 鏈接分配一個TCP 控制塊(TCP control block or TCB),這個控制塊用於緩存TCP鏈接的一些參數,每一個TCB須要分配 0.5 KB的pagepool 和 0.5KB 的Non-pagepool,也就說,每一個TCP鏈接會佔用 1KB 的系統內存。

系統的最大TCB數量由以下注冊表設置決定

[HKEY_LOCAL_MACHINE \System \CurrentControlSet \Services \Tcpip \Parameters]
MaxFreeTcbs = 2000 (Default = RAM dependent, but usual Pro = 1000, Srv=2000)

非Server版本,MaxFreeTcbs 的默認值爲1000 (64M 以上物理內存)

Server 版本,這個的默認值爲 2000。

也就是說,默認狀況下,Server 版本最多同時能夠創建並保持2000個TCP 鏈接。

最大TCB Hash table 數量
TCB 是經過Hash table 來管理的,下面註冊表設置決定了這個Hash table 的大小

HKEY_LOCAL_MACHINE \System \CurrentControlSet \services \Tcpip \Parameters]
MaxHashTableSize = 512 (Default = 512, Range = 64-65536)

這個值指明分配 pagepool 內存的數量,也就是說,若是MaxFreeTcbs = 1000 , 則 pagepool 的內存數量爲 500KB

那麼 MaxHashTableSize 應大於 500 才行。這個數量越大,則Hash table 的冗餘度就越高,每次分配和查找 TCP  鏈接用時就越少。這個值必須是2的冪,且最大爲65536.

 

IBM WebSphere Voice Server 在windows server 2003 下的典型配置
這是IBM WebSphere Voice Server 的典型配置,你們能夠作個參考。原文參見

IBM Web Sphere Voice Server 配置

 

•MaxUserPort = 65534 (Decimal)
•MaxHashTableSize = 65536 (Decimal)
•MaxFreeTcbs = 16000 (Decimal) 
這裏咱們能夠看到 MaxHashTableSize 被配置爲比MaxFreeTcbs 大4倍,這樣能夠大大增長TCP創建的速度。

 

http://www.zhihu.com/question/30772664

 

如今 epoll 單機(4G內存)併發量最大能達到多少?修改

寫補充說明

舉報

 添加評論 分享 • 邀請回答

按投票排序按時間排序

2 個回答

 

張亞偉,zsummerX, log4z做者.

馬劍飛夢覺孫鵬 等人贊同

按照題主的意思 是根據內存去算一個最大併發的鏈接數. 那麼首先要找出來單個鏈接消耗內存的地方.
第一個首先是socket buffer. read 和write 分別有一個, 默認大小在

  • /proc/sys/net/ipv4/tcp_rmem (for read)
  • /proc/sys/net/ipv4/tcp_wmem (for write)

默認大小都是87K和16K, 最低是4K和4K, 最高是2M,2M, 實際使用默認值最低也要保留8K,8K.

而後是邏輯IO緩衝區
就是好比你監聽了recv事件 事件來了 你要有內存可用(通常都是socket創建起就分配好,斷開纔會釋放的).
這個內存是本身寫socket程序時候本身控制的, 最低也要4K,4K, 實際使用8K,8K至少.

如今設定一個優化方案和使用場景, 首先假設4G內存所有爲空閒(系統和其餘進程也要內存的....

假如網絡包的大小均可以控制在4K如下, 假設全部鏈接的網絡都不會擁堵, 或者擁堵時候的總量在4K如下:
一個鏈接的內存消耗是4+4+4+4=16K
4G/16K=26.2萬併發

假如網絡包的大小均可以控制在8K如下, 假設全部鏈接的網絡都不會擁堵, 或者擁堵時候的總量在8K如下
一個socket的內存佔用介於 24K ~ 32K之間, 保守的按照32K算 
4G/32K=13.1萬併發, 這個在生產環境做爲一個純網絡層面的內存消耗, 是能夠做爲參考的.

假如使用默認配置, 假如全部鏈接的網絡都出現嚴重擁堵, 不考慮邏輯上的發送隊列的佔用,
使用默認配置是2M+2M+8+8 ~= 4M
4G/4M=1024併發 ( ...
若是考慮到發送隊列也擁堵的話 本身腦補.


若是隻是爲了跑分 爲了併發而優化, 沒有常駐的邏輯緩衝區 而且socket的網絡吞吐量很小而且負載平滑, 把socket buffer size設置系統最低.
那麼是
4G/8K = 52.4萬併發 這個應該是極限值了.

相關文章
相關標籤/搜索