Jack Jiang

          我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
          posts - 499, comments - 13, trackbacks - 0, articles - 1

          本文作者張彥飛,原題“127.0.0.1 之本機網(wǎng)絡通信過程知多少 ”,首次發(fā)布于“開發(fā)內(nèi)功修煉”,轉(zhuǎn)載請聯(lián)系作者。本次有改動。

          1、引言

          繼《你真的了解127.0.0.1和0.0.0.0的區(qū)別?》之后,這是我整理的第2篇有關本機網(wǎng)絡方面的網(wǎng)絡編程基礎文章。

          這次的文章由作者張彥飛原創(chuàng)分享,寫作本文的原因是現(xiàn)在本機網(wǎng)絡 IO 應用非常廣。在 php 中 一般 Nginx 和 php-fpm 是通過 127.0.0.1 來進行通信的;在微服務中,由于 side car 模式的應用,本機網(wǎng)絡請求更是越來越多。所以,如果能深度理解這個問題在各種網(wǎng)絡通信應用的技術實踐中將非常的有意義。

          今天咱們就把 127.0.0.1 本機網(wǎng)絡通信相關問題搞搞清楚!

          為了方便討論,我把這個問題拆分成3問:

          • 1)127.0.0.1 本機網(wǎng)絡 IO 需要經(jīng)過網(wǎng)卡嗎?
          • 2)和外網(wǎng)網(wǎng)絡通信相比,在內(nèi)核收發(fā)流程上有啥差別?
          • 3)使用 127.0.0.1 能比 192.168.x 更快嗎?

          上面這幾個問題,相信包括常期混跡于即時通訊網(wǎng)的即時通訊老鳥們在內(nèi),都是看似很熟悉,但實則仍然無法透徹講清楚的話題。這次,我們就來徹底搞清楚!

          本文同步發(fā)布于:http://www.52im.net/thread-3600-1-1.html

          2、系列文章

          本文是系列文章中的第13篇,本系列文章的大綱如下:

          不為人知的網(wǎng)絡編程(一):淺析TCP協(xié)議中的疑難雜癥(上篇)

          不為人知的網(wǎng)絡編程(二):淺析TCP協(xié)議中的疑難雜癥(下篇)

          不為人知的網(wǎng)絡編程(三):關閉TCP連接時為什么會TIME_WAIT、CLOSE_WAIT

          不為人知的網(wǎng)絡編程(四):深入研究分析TCP的異常關閉

          不為人知的網(wǎng)絡編程(五):UDP的連接性和負載均衡

          不為人知的網(wǎng)絡編程(六):深入地理解UDP協(xié)議并用好它

          不為人知的網(wǎng)絡編程(七):如何讓不可靠的UDP變的可靠?

          不為人知的網(wǎng)絡編程(八):從數(shù)據(jù)傳輸層深度解密HTTP

          不為人知的網(wǎng)絡編程(九):理論聯(lián)系實際,全方位深入理解DNS

          不為人知的網(wǎng)絡編程(十):深入操作系統(tǒng),從內(nèi)核理解網(wǎng)絡包的接收過程(Linux篇)

          不為人知的網(wǎng)絡編程(十一):從底層入手,深度分析TCP連接耗時的秘密

          不為人知的網(wǎng)絡編程(十二):徹底搞懂TCP協(xié)議層的KeepAlive保活機制

          不為人知的網(wǎng)絡編程(十三):深入操作系統(tǒng),徹底搞懂127.0.0.1本機網(wǎng)絡通信》(* 本文

          3、作為對比,先看看跨機網(wǎng)路通信

          在開始講述本機通信過程之前,我們先看看跨機網(wǎng)絡通信(以Linux系統(tǒng)內(nèi)核中的實現(xiàn)為例來講解)。

          3.1 跨機數(shù)據(jù)發(fā)送

          從 send 系統(tǒng)調(diào)用開始,直到網(wǎng)卡把數(shù)據(jù)發(fā)送出去,整體流程如下:

          在上面這幅圖中,我們看到用戶數(shù)據(jù)被拷貝到內(nèi)核態(tài),然后經(jīng)過協(xié)議棧處理后進入到了 RingBuffer 中。隨后網(wǎng)卡驅(qū)動真正將數(shù)據(jù)發(fā)送了出去。當發(fā)送完成的時候,是通過硬中斷來通知 CPU,然后清理 RingBuffer。

          不過上面這幅圖并沒有很好地把內(nèi)核組件和源碼展示出來,我們再從代碼的視角看一遍。

          等網(wǎng)絡發(fā)送完畢之后。網(wǎng)卡在發(fā)送完畢的時候,會給 CPU 發(fā)送一個硬中斷來通知 CPU。收到這個硬中斷后會釋放 RingBuffer 中使用的內(nèi)存。

          3.2 跨機數(shù)據(jù)接收

          當數(shù)據(jù)包到達另外一臺機器的時候,Linux 數(shù)據(jù)包的接收過程開始了(更詳細的講解可以看看《深入操作系統(tǒng),從內(nèi)核理解網(wǎng)絡包的接收過程(Linux篇)》)。

          ▲ 上圖引用自《深入操作系統(tǒng),從內(nèi)核理解網(wǎng)絡包的接收過程(Linux篇)

          當網(wǎng)卡收到數(shù)據(jù)以后,CPU發(fā)起一個中斷,以通知 CPU 有數(shù)據(jù)到達。當CPU收到中斷請求后,會去調(diào)用網(wǎng)絡驅(qū)動注冊的中斷處理函數(shù),觸發(fā)軟中斷。ksoftirqd 檢測到有軟中斷請求到達,開始輪詢收包,收到后交由各級協(xié)議棧處理。當協(xié)議棧處理完并把數(shù)據(jù)放到接收隊列的之后,喚醒用戶進程(假設是阻塞方式)。

          我們再同樣從內(nèi)核組件和源碼視角看一遍。

          3.3 跨機網(wǎng)絡通信匯總

          關于跨機網(wǎng)絡通信的理解,可以通俗地用下面這張圖來總結一下:

          4、本機網(wǎng)絡數(shù)據(jù)的發(fā)送過程

          在上一節(jié)中,我們看到了跨機時整個網(wǎng)絡數(shù)據(jù)的發(fā)送過程 。

          在本機網(wǎng)絡 IO 的過程中,流程會有一些差別。為了突出重點,本節(jié)將不再介紹整體流程,而是只介紹和跨機邏輯不同的地方。有差異的地方總共有兩個,分別是路由和驅(qū)動程序。

          4.1 網(wǎng)絡層路由

          發(fā)送數(shù)據(jù)會進入?yún)f(xié)議棧到網(wǎng)絡層的時候,網(wǎng)絡層入口函數(shù)是 ip_queue_xmit。在網(wǎng)絡層里會進行路由選擇,路由選擇完畢后,再設置一些 IP 頭、進行一些 netfilter 的過濾后,將包交給鄰居子系統(tǒng)。

          對于本機網(wǎng)絡 IO 來說,特殊之處在于在 local 路由表中就能找到路由項,對應的設備都將使用 loopback 網(wǎng)卡,也就是我們常見的 lO。

          我們來詳細看看路由網(wǎng)絡層里這段路由相關工作過程。從網(wǎng)絡層入口函數(shù) ip_queue_xmit 看起。

          //file: net/ipv4/ip_output.c

          intip_queue_xmit(struct sk_buff *skb, struct flowi *fl)

          {

           //檢查 socket 中是否有緩存的路由表

           rt = (struct rtable *)__sk_dst_check(sk, 0);

           if(rt == NULL) {

            //沒有緩存則展開查找

            //則查找路由項, 并緩存到 socket 中

            rt = ip_route_output_ports(...);

            sk_setup_caps(sk, &rt->dst);

           }

          查找路由項的函數(shù)是 ip_route_output_ports,它又依次調(diào)用到 ip_route_output_flow、__ip_route_output_key、fib_lookup。調(diào)用過程省略掉,直接看 fib_lookup 的關鍵代碼。

          //file:include/net/ip_fib.h

          static inline int fib_lookup(struct net *net, const struct flowi4 *flp, struct fib_result *res)

          {

           struct fib_table *table;

           

           table = fib_get_table(net, RT_TABLE_LOCAL);

           if(!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))

            return 0;

           

           table = fib_get_table(net, RT_TABLE_MAIN);

           if(!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))

            return 0;

           return -ENETUNREACH;

          }

          在 fib_lookup 將會對 local 和 main 兩個路由表展開查詢,并且是先查 local 后查詢 main。我們在 Linux 上使用命令名可以查看到這兩個路由表, 這里只看 local 路由表(因為本機網(wǎng)絡 IO 查詢到這個表就終止了)。

          #ip route list table local

          local10.143.x.y dev eth0 proto kernel scope host src 10.143.x.y

          local127.0.0.1 dev lo proto kernel scope host src 127.0.0.1

          從上述結果可以看出,對于目的是 127.0.0.1 的路由在 local 路由表中就能夠找到了。fib_lookup 工作完成,返回__ip_route_output_key 繼續(xù)。

          //file: net/ipv4/route.c

          struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)

          {

           if(fib_lookup(net, fl4, &res)) {

           }

           if(res.type == RTN_LOCAL) {

            dev_out = net->loopback_dev;

            ...

           }

           

           rth = __mkroute_output(&res, fl4, orig_oif, dev_out, flags);

           return rth;

          }

          對于是本機的網(wǎng)絡請求,設備將全部都使用 net->loopback_dev,也就是 lo 虛擬網(wǎng)卡。

          接下來的網(wǎng)絡層仍然和跨機網(wǎng)絡 IO 一樣,最終會經(jīng)過 ip_finish_output,最終進入到 鄰居子系統(tǒng)的入口函數(shù) dst_neigh_output 中。

          本機網(wǎng)絡 IO 需要進行 IP 分片嗎?因為和正常的網(wǎng)絡層處理過程一樣會經(jīng)過 ip_finish_output 函數(shù)。在這個函數(shù)中,如果 skb 大于 MTU 的話,仍然會進行分片。只不過 lo 的 MTU 比 Ethernet 要大很多。通過 ifconfig 命令就可以查到,普通網(wǎng)卡一般為 1500,而 lO 虛擬接口能有 65535。

          在鄰居子系統(tǒng)函數(shù)中經(jīng)過處理,進入到網(wǎng)絡設備子系統(tǒng)(入口函數(shù)是 dev_queue_xmit)。

          4.2 網(wǎng)絡設備子系統(tǒng)

          網(wǎng)絡設備子系統(tǒng)的入口函數(shù)是 dev_queue_xmit。簡單回憶下之前講述跨機發(fā)送過程的時候,對于真的有隊列的物理設備,在該函數(shù)中進行了一系列復雜的排隊等處理以后,才調(diào)用 dev_hard_start_xmit,從這個函數(shù) 再進入驅(qū)動程序來發(fā)送。

          在這個過程中,甚至還有可能會觸發(fā)軟中斷來進行發(fā)送,流程如圖:

          但是對于啟動狀態(tài)的回環(huán)設備來說(q->enqueue 判斷為 false),就簡單多了:沒有隊列的問題,直接進入 dev_hard_start_xmit。接著進入回環(huán)設備的“驅(qū)動”里的發(fā)送回調(diào)函數(shù) loopback_xmit,將 skb “發(fā)送”出去。

          我們來看下詳細的過程,從網(wǎng)絡設備子系統(tǒng)的入口 dev_queue_xmit 看起。

          //file: net/core/dev.c

          int dev_queue_xmit(struct sk_buff *skb)

          {

           q = rcu_dereference_bh(txq->qdisc);

           if(q->enqueue) {//回環(huán)設備這里為 false

            rc = __dev_xmit_skb(skb, q, dev, txq);

            goto out;

           }

           

           //開始回環(huán)設備處理

           if(dev->flags & IFF_UP) {

            dev_hard_start_xmit(skb, dev, txq, ...);

            ...

           }

          }

          在 dev_hard_start_xmit 中還是將調(diào)用設備驅(qū)動的操作函數(shù)。

          //file: net/core/dev.c

          int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq)

          {

           //獲取設備驅(qū)動的回調(diào)函數(shù)集合 ops

           const struct net_device_ops *ops = dev->netdev_ops;

           

           //調(diào)用驅(qū)動的 ndo_start_xmit 來進行發(fā)送

           rc = ops->ndo_start_xmit(skb, dev);

           ...

          }

          4.3 “驅(qū)動”程序

          對于真實的 igb 網(wǎng)卡來說,它的驅(qū)動代碼都在 drivers/net/ethernet/intel/igb/igb_main.c 文件里。順著這個路子,我找到了 loopback 設備的“驅(qū)動”代碼位置:drivers/net/loopback.c

          在 drivers/net/loopback.c:

          //file:drivers/net/loopback.c

          static const struct net_device_ops loopback_ops = {

           .ndo_init      = loopback_dev_init,

           .ndo_start_xmit = loopback_xmit,

           .ndo_get_stats64 = loopback_get_stats64,

          };

          所以對 dev_hard_start_xmit 調(diào)用實際上執(zhí)行的是 loopback “驅(qū)動” 里的 loopback_xmit。

          為什么我把“驅(qū)動”加個引號呢,因為 loopback 是一個純軟件性質(zhì)的虛擬接口,并沒有真正意義上的驅(qū)動,它的工作流程大致如圖。

          我們再來看詳細的代碼。

          //file:drivers/net/loopback.c

          static netdev_tx_t loopback_xmit(struct sk_buff *skb, struct net_device *dev)

          {

           //剝離掉和原 socket 的聯(lián)系

           skb_orphan(skb);

           

           //調(diào)用netif_rx

           if(likely(netif_rx(skb) == NET_RX_SUCCESS)) {

           }

          }

          在 skb_orphan 中先是把 skb 上的 socket 指針去掉了(剝離了出來)。

          注意:在本機網(wǎng)絡 IO 發(fā)送的過程中,傳輸層下面的 skb 就不需要釋放了,直接給接收方傳過去就行了。總算是省了一點點開銷。不過可惜傳輸層的 skb 同樣節(jié)約不了,還是得頻繁地申請和釋放。

          接著調(diào)用 netif_rx,在該方法中 中最終會執(zhí)行到 enqueue_to_backlog 中(netif_rx -> netif_rx_internal -> enqueue_to_backlog)。

          //file: net/core/dev.c

          static int enqueue_to_backlog(struct sk_buff *skb, int cpu, unsigned int *qtail)

          {

           sd = &per_cpu(softnet_data, cpu);

           ...

           __skb_queue_tail(&sd->input_pkt_queue, skb);

           ...

           ____napi_schedule(sd, &sd->backlog);

          在 enqueue_to_backlog 把要發(fā)送的 skb 插入 softnet_data->input_pkt_queue 隊列中并調(diào)用 ____napi_schedule 來觸發(fā)軟中斷。

          //file:net/core/dev.c

          static inline void ____napi_schedule(struct softnet_data *sd, struct napi_struct *napi)

          {

           list_add_tail(&napi->poll_list, &sd->poll_list);

           __raise_softirq_irqoff(NET_RX_SOFTIRQ);

          }

          只有觸發(fā)完軟中斷,發(fā)送過程就算是完成了。

          5、本機網(wǎng)絡數(shù)據(jù)的接收過程

          5.1 主要過程

          在跨機的網(wǎng)絡包的接收過程中,需要經(jīng)過硬中斷,然后才能觸發(fā)軟中斷。

          而在本機的網(wǎng)絡 IO 過程中,由于并不真的過網(wǎng)卡,所以網(wǎng)卡實際傳輸,硬中斷就都省去了。直接從軟中斷開始,經(jīng)過 process_backlog 后送進協(xié)議棧,大體過程如下圖。

          5.2 詳細過程

          接下來我們再看更詳細一點的過程。

          在軟中斷被觸發(fā)以后,會進入到 NET_RX_SOFTIRQ 對應的處理方法 net_rx_action 中(至于細節(jié)參見《深入操作系統(tǒng),從內(nèi)核理解網(wǎng)絡包的接收過程(Linux篇)》一文中的 4.2 小節(jié))。

          //file: net/core/dev.c

          static void net_rx_action(struct softirq_action *h){

           while(!list_empty(&sd->poll_list)) {

            work = n->poll(n, weight);

           }

          }

          我們還記得對于 igb 網(wǎng)卡來說,poll 實際調(diào)用的是 igb_poll 函數(shù)。

          那么 loopback 網(wǎng)卡的 poll 函數(shù)是誰呢?由于poll_list 里面是 struct softnet_data 對象,我們在 net_dev_init 中找到了蛛絲馬跡。

          //file:net/core/dev.c

          static int __init net_dev_init(void)

          {

           for_each_possible_cpu(i) {

            sd->backlog.poll = process_backlog;

           }

          }

          原來struct softnet_data 默認的 poll 在初始化的時候設置成了 process_backlog 函數(shù),來看看它都干了啥。

          static int process_backlog(struct napi_struct *napi, int quota)

          {

           while(){

            while((skb = __skb_dequeue(&sd->process_queue))) {

             __netif_receive_skb(skb);

            }

            //skb_queue_splice_tail_init()函數(shù)用于將鏈表a連接到鏈表b上,

            //形成一個新的鏈表b,并將原來a的頭變成空鏈表。

            qlen = skb_queue_len(&sd->input_pkt_queue);

            if(qlen)

             skb_queue_splice_tail_init(&sd->input_pkt_queue, &sd->process_queue);

           }

          }

          這次先看對 skb_queue_splice_tail_init 的調(diào)用。源碼就不看了,直接說它的作用是把 sd->input_pkt_queue 里的 skb 鏈到 sd->process_queue 鏈表上去。

          然后再看 __skb_dequeue, __skb_dequeue 是從 sd->process_queue 上取下來包來處理。這樣和前面發(fā)送過程的結尾處就對上了。發(fā)送過程是把包放到了 input_pkt_queue 隊列里,接收過程是在從這個隊列里取出 skb。

          最后調(diào)用 __netif_receive_skb 將 skb(數(shù)據(jù)) 送往協(xié)議棧。在此之后的調(diào)用過程就和跨機網(wǎng)絡 IO 又一致了。

          送往協(xié)議棧的調(diào)用鏈是 __netif_receive_skb => __netif_receive_skb_core => deliver_skb 后 將數(shù)據(jù)包送入到 ip_rcv 中(詳情參見《深入操作系統(tǒng),從內(nèi)核理解網(wǎng)絡包的接收過程(Linux篇)》一文中的 4.3 小節(jié))。

          網(wǎng)絡再往后依次是傳輸層,最后喚醒用戶進程,這里就不多展開了。

          6、本機網(wǎng)絡通信過程小結

          我們來總結一下本機網(wǎng)絡通信的內(nèi)核執(zhí)行流程:

          回想下跨機網(wǎng)絡 IO 的流程是:

          好了,回到正題,我們終于可以在單獨的章節(jié)里回答開篇的三個問題啦。

          7、開篇三個問題的答案

          1)問題1:127.0.0.1 本機網(wǎng)絡 IO 需要經(jīng)過網(wǎng)卡嗎?

          通過本文的敘述,我們確定地得出結論,不需要經(jīng)過網(wǎng)卡。即使了把網(wǎng)卡拔了本機網(wǎng)絡是否還可以正常使用的。

          2)問題2:數(shù)據(jù)包在內(nèi)核中是個什么走向,和外網(wǎng)發(fā)送相比流程上有啥差別?

          總的來說,本機網(wǎng)絡 IO 和跨機 IO 比較起來,確實是節(jié)約了一些開銷。發(fā)送數(shù)據(jù)不需要進 RingBuffer 的驅(qū)動隊列,直接把 skb 傳給接收協(xié)議棧(經(jīng)過軟中斷)。

          但是在內(nèi)核其它組件上可是一點都沒少:系統(tǒng)調(diào)用、協(xié)議棧(傳輸層、網(wǎng)絡層等)、網(wǎng)絡設備子系統(tǒng)、鄰居子系統(tǒng)整個走了一個遍。連“驅(qū)動”程序都走了(雖然對于回環(huán)設備來說只是一個純軟件的虛擬出來的東東)。所以即使是本機網(wǎng)絡 IO,也別誤以為沒啥開銷

          3)問題3:使用 127.0.0.1 能比 192.168.x 更快嗎?

          先說結論:我認為這兩種使用方法在性能上沒有啥差別。

          我覺得有相當大一部分人都會認為訪問本機 Server 的話,用 127.0.0.1 更快。原因是直覺上認為訪問 IP 就會經(jīng)過網(wǎng)卡。

          其實內(nèi)核知道本機上所有的 IP,只要發(fā)現(xiàn)目的地址是本機 IP 就可以全走 loopback 回環(huán)設備了。本機其它 IP 和 127.0.0.1 一樣,也是不用過物理網(wǎng)卡的,所以訪問它們性能開銷基本一樣!

          附錄:更多網(wǎng)絡編程系列文章

          如果您覺得本系列文章過于專業(yè),您可先閱讀《網(wǎng)絡編程懶人入門》系列文章,該系列目錄如下:

          網(wǎng)絡編程懶人入門(一):快速理解網(wǎng)絡通信協(xié)議(上篇)

          網(wǎng)絡編程懶人入門(二):快速理解網(wǎng)絡通信協(xié)議(下篇)

          網(wǎng)絡編程懶人入門(三):快速理解TCP協(xié)議一篇就夠

          網(wǎng)絡編程懶人入門(四):快速理解TCP和UDP的差異

          網(wǎng)絡編程懶人入門(五):快速理解為什么說UDP有時比TCP更有優(yōu)勢

          網(wǎng)絡編程懶人入門(六):史上最通俗的集線器、交換機、路由器功能原理入門

          網(wǎng)絡編程懶人入門(七):深入淺出,全面理解HTTP協(xié)議

          網(wǎng)絡編程懶人入門(八):手把手教你寫基于TCP的Socket長連接

          網(wǎng)絡編程懶人入門(九):通俗講解,有了IP地址,為何還要用MAC地址?

          網(wǎng)絡編程懶人入門(十):一泡尿的時間,快速讀懂QUIC協(xié)議

          網(wǎng)絡編程懶人入門(十一):一文讀懂什么是IPv6

          網(wǎng)絡編程懶人入門(十二):快速讀懂Http/3協(xié)議,一篇就夠!

          本站的《腦殘式網(wǎng)絡編程入門》也適合入門學習,本系列大綱如下:

          腦殘式網(wǎng)絡編程入門(一):跟著動畫來學TCP三次握手和四次揮手

          腦殘式網(wǎng)絡編程入門(二):我們在讀寫Socket時,究竟在讀寫什么?

          腦殘式網(wǎng)絡編程入門(三):HTTP協(xié)議必知必會的一些知識

          腦殘式網(wǎng)絡編程入門(四):快速理解HTTP/2的服務器推送(Server Push)

          腦殘式網(wǎng)絡編程入門(五):每天都在用的Ping命令,它到底是什么?

          腦殘式網(wǎng)絡編程入門(六):什么是公網(wǎng)IP和內(nèi)網(wǎng)IP?NAT轉(zhuǎn)換又是什么鬼?

          腦殘式網(wǎng)絡編程入門(七):面視必備,史上最通俗計算機網(wǎng)絡分層詳解

          腦殘式網(wǎng)絡編程入門(八):你真的了解127.0.0.1和0.0.0.0的區(qū)別?

          腦殘式網(wǎng)絡編程入門(九):面試必考,史上最通俗大小端字節(jié)序詳解

          以下資料來自《TCP/IP詳解》,入門者必讀:

          TCP/IP詳解 - 第11章·UDP:用戶數(shù)據(jù)報協(xié)議

          TCP/IP詳解 - 第17章·TCP:傳輸控制協(xié)議

          TCP/IP詳解 - 第18章·TCP連接的建立與終止

          TCP/IP詳解 - 第21章·TCP的超時與重傳

          以下系列適合服務端網(wǎng)絡編程開發(fā)者閱讀:

          高性能網(wǎng)絡編程(一):單臺服務器并發(fā)TCP連接數(shù)到底可以有多少

          高性能網(wǎng)絡編程(二):上一個10年,著名的C10K并發(fā)連接問題

          高性能網(wǎng)絡編程(三):下一個10年,是時候考慮C10M并發(fā)問題了

          高性能網(wǎng)絡編程(四):從C10K到C10M高性能網(wǎng)絡應用的理論探索

          高性能網(wǎng)絡編程(五):一文讀懂高性能網(wǎng)絡編程中的I/O模型

          高性能網(wǎng)絡編程(六):一文讀懂高性能網(wǎng)絡編程中的線程模型

          高性能網(wǎng)絡編程(七):到底什么是高并發(fā)?一文即懂!

          從根上理解高性能、高并發(fā)(一):深入計算機底層,理解線程與線程池

          從根上理解高性能、高并發(fā)(二):深入操作系統(tǒng),理解I/O與零拷貝技術

          從根上理解高性能、高并發(fā)(三):深入操作系統(tǒng),徹底理解I/O多路復用

          從根上理解高性能、高并發(fā)(四):深入操作系統(tǒng),徹底理解同步與異步

          從根上理解高性能、高并發(fā)(五):深入操作系統(tǒng),理解高并發(fā)中的協(xié)程

          從根上理解高性能、高并發(fā)(六):通俗易懂,高性能服務器到底是如何實現(xiàn)的

          從根上理解高性能、高并發(fā)(七):深入操作系統(tǒng),一文讀懂進程、線程、協(xié)程

          以下系列適合移動端資深網(wǎng)絡通信開發(fā)者閱讀:

          IM開發(fā)者的零基礎通信技術入門(一):通信交換技術的百年發(fā)展史(上)

          IM開發(fā)者的零基礎通信技術入門(二):通信交換技術的百年發(fā)展史(下)

          IM開發(fā)者的零基礎通信技術入門(三):國人通信方式的百年變遷

          IM開發(fā)者的零基礎通信技術入門(四):手機的演進,史上最全移動終端發(fā)展史

          IM開發(fā)者的零基礎通信技術入門(五):1G到5G,30年移動通信技術演進史

          IM開發(fā)者的零基礎通信技術入門(六):移動終端的接頭人——“基站”技術

          IM開發(fā)者的零基礎通信技術入門(七):移動終端的千里馬——“電磁波”

          IM開發(fā)者的零基礎通信技術入門(八):零基礎,史上最強“天線”原理掃盲

          IM開發(fā)者的零基礎通信技術入門(九):無線通信網(wǎng)絡的中樞——“核心網(wǎng)”

          IM開發(fā)者的零基礎通信技術入門(十):零基礎,史上最強5G技術掃盲

          IM開發(fā)者的零基礎通信技術入門(十一):為什么WiFi信號差?一文即懂!

          IM開發(fā)者的零基礎通信技術入門(十二):上網(wǎng)卡頓?網(wǎng)絡掉線?一文即懂!

          IM開發(fā)者的零基礎通信技術入門(十三):為什么手機信號差?一文即懂!

          IM開發(fā)者的零基礎通信技術入門(十四):高鐵上無線上網(wǎng)有多難?一文即懂!

          IM開發(fā)者的零基礎通信技術入門(十五):理解定位技術,一篇就夠

          本文已同步發(fā)布于“即時通訊技術圈”公眾號。

          ▲ 本文在公眾號上的鏈接是:點此進入。同步發(fā)布鏈接是:http://www.52im.net/thread-3600-1-1.html



          作者:Jack Jiang (點擊作者姓名進入Github)
          出處:http://www.52im.net/space-uid-1.html
          交流:歡迎加入即時通訊開發(fā)交流群 215891622
          討論:http://www.52im.net/
          Jack Jiang同時是【原創(chuàng)Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
          本博文 歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處(也可前往 我的52im.net 找到我)。


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 新巴尔虎左旗| 原平市| 重庆市| 郎溪县| 宁城县| 澄迈县| 锡林浩特市| 奉贤区| 监利县| 弥渡县| 宽城| 黄山市| 富阳市| 奉贤区| 抚远县| 苏州市| 闵行区| 昌吉市| 安龙县| 莆田市| 报价| 柯坪县| 宁阳县| 朝阳市| 师宗县| 凭祥市| 定襄县| 威海市| 高州市| 富川| 澄迈县| 迭部县| 乐昌市| 石泉县| 鱼台县| 太白县| 古浪县| 视频| 龙川县| 花垣县| 六枝特区|