網絡編程學習-面向工資編程-讀書筆記

接上一篇 http://www.cnblogs.com/charlesblc/p/6241926.htmlphp

 

來源:html

https://zhuanlan.zhihu.com/p/20204159程序員

(一):演進——從Apache到Nginx

網上關於Apache和Nginx性能比較的文章很是多,基本上有以下的定論:編程

  1. Nginx在併發性能上比Apache強不少,若是是純靜態資源(圖片、JS、CSS)那麼Nginx是不二之選。
  2. Apache有mod_php、在PHP類的應用場景下比Nginx部署起來簡單不少。一些老的PHP項目用Apache 來配置運行很是的簡單,例如Wordpress。
  3. 對於初學者來講Apache配置起來很是複雜冗長的類XML語法,甚至支持在子目錄放置.htaccess 文件來配置子目錄的屬性。Nginx的配置文件相對簡單一點。
  4. Nginx的模塊比較容易寫,能夠經過寫C的mod實現接口性質的服務,而且擁有驚人的性能。 分支OpenResty,能夠配合lua來實現不少自定義功能,兼顧擴展性和性能。

 

這裏咱們要着重討論的是爲何 Nginx在併發性能上比Apache要好不少
 

非阻塞&事件驅動這麼好,爲何你們沒有一開始就採用這種方式呢? 緣由有二:瀏覽器

  1. 非阻塞&事件驅動須要系統的支持,提供non-blocking版的整套 系統調用。
  2. 非阻塞&事件驅動編程難度較大,須要很高的抽象思惟能力, 把整個任務拆解;採用有限狀態機編程才能實現。
 
第二篇:
 
下面這段摘自wikipedia:

epoll是Linux內核的可擴展I/O事件通知機制。它設計目的只在取代既有POSIX select(2)與poll(2)系統函數,讓須要大量操做文件描述符的程序得以發揮更優異的性能 (舉例來講:舊有的系統函數所花費的時間複雜度爲O(n),epoll則耗時O(1))。 epoll與FreeBSD的kqueue相似,底層都是由可配置的操做系統內核對象建構而成, 並以文件描述符(file descriptor)的形式呈現於用戶空間。服務器

 

epoll由下面幾個系統調用組成:網絡

int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event); int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); 

爲了解決高併發問題,大約在2000年,Jonathan Lemon在FreeBSD內核中實現了第一個版本 的kqueue,並在FreeBSD 4.1版本發佈。以後FreeBSD在處理高併發的問題上一直領先於Linux。併發


在2002年,Linux的2.5.44版本(測試版本)首次加入了epoll機制。 直到2004年,在Linux的2.6.9版本epoll相關的API才穩定下來, Linux的高併發機制這纔跟遇上FreeBSD。
 

各類操做系統在解決這個問題的辦法上也是百花齊放:框架

技術操做系統kqueueUNIX (FreeBSD、MacOS)epollLinux 2.5.44/2.6.9IOCP (IO Completion Port)Windows NT 3.5, AIX, Solaris 10

 

第三篇
 

Libevent

 

因爲POSIX標準的滯後性,事件通知API的混亂一直保持到如今, 全部就有 libevent、libev甚至後面的libuv的出現爲跨平臺編程掃清障礙
 

下面是WikiPedia對於libevent的介紹:異步

libevent是一個異步事件處理軟件函式庫,以BSD許可證發佈。 libevent提供了一組應用程序編程接口(API),讓程序員能夠設定某些事件發生時所執行的函式,也就是說,libevent能夠用來取代網絡服務器所使用的事件循環檢查框架

因爲能夠省去對網絡的處理,且擁有不錯的效能, 有些軟件使用libevent做爲網絡底層的函式庫,如:Chromium(Chrome的開源版)、 memcached、Tor。

按照libevent的官方網站,libevent庫提供瞭如下功能:當一個文件描述符的特定事件 (如可讀,可寫或出錯)發生了,或一個定時事件發生了, libevent就會自動執行用戶指定的回調函數,來處理事件。


libevent的高明之處還在於,它把fd讀寫、信號、DNS、定時器甚至idle(空閒) 都抽象化成了event(事件)。
 
 
ET/LT區別

兩者的差別在於Level Triggered模式下只要某個socket處於readable/writable狀態, 不管何時進行epoll_wait都會返回該socket;

而Edge Triggered模式下只有某個socket從unreadable變爲readable或 從unwritable變爲writable時,epoll_wait纔會返回該socket。



第四篇
https://zhuanlan.zhihu.com/p/20336461?refer=auxten
 
 
第五篇

TCP的「鏈接」僅僅是鏈接的兩端對於四元組和sequence號的一種約定而已。


在有些文章裏總會提到這名詞、或者五元組,甚至七元組。 雖然我很反對擺弄名詞秀專業,但咱們也要防止被「秀」。 其實很容易理解:

  • 四元組: 源IP地址、目的IP地址、源端口、目的端口
  • 五元組: 源IP地址、目的IP地址、協議、源端口、目的端口
  • 七元組: 源IP地址、目的IP地址、協議、源端口、目的端口,服務類型,接口索引

 

在 HTTP 1.0 中, 沒有官方的 keepalive 的操做。一般是在現有協議上添加一個指數。 若是瀏覽器支持 keep-alive,它會在請求的包頭中添加:

Connection: Keep-Alive

而後當服務器收到請求,做出迴應的時候,它也添加一個頭在響應中:

Connection: Keep-Alive

這樣作,鏈接就不會中斷,而是保持鏈接。

在 HTTP 1.1 中 全部的鏈接默認都是持續鏈接,除非特殊聲明不支持。
然而,Apache 2.0 httpd 的默認鏈接過時時間是僅僅15秒,對於 Apache 2.2 只有5秒。
 
 

動靜分離

爲了規避上面說的對圖片等靜態資源的影響,大多數商業網站會啓用獨立的靜態資源域名。 從而保證主站的動態資源請求和靜態資源的請求不會互相擠佔鏈接。

動靜分離同時還會有一個額外的好處:

對於靜態資源的請求,HTTP請求頭裏的Cookie等信息是沒有用處的, 反而佔用了寶貴的上行網絡資源。用獨立的域名存放靜態資源後, 請求靜態資源域名就不會默認帶上主站域的Cookie,從而解決了這個問題。

以下表:

 

第六篇 端口

https://zhuanlan.zhihu.com/p/20365900?refer=auxten
 

0號端口

端口號裏有一個極爲特殊的端口,各類文檔書籍中都鮮有記載,就是0號端口。

在IANA官方的標準裏0號端口是保留端口。

 

然而,標準歸標準,在UNIX/Linux網絡編程中0號端口被賦予了特殊的涵義:

若是在bind綁定的時候指定端口0,意味着由系統隨機選擇一個可用端口來綁定。

 

網絡地址轉換NAT

NAT是"Network Address Translation"的縮寫,直譯就是網絡地址轉換。 1990年代中期,爲了應對IPv4地址短缺,NAT技術流行起來。

 

NAT技術的普遍應用也給不少應用帶來了極大的麻煩: 處於NAT網絡環境內的服務器很難被外部的網絡程序主動鏈接,受這一點傷害最大的莫過於: 點對點視頻、語音、文件傳輸類的程序。

固然咱們聰明的工程師通過長時間的努力,發明了「NAT打洞」技術,必定程度上解決了此類問題。



多進程端口監聽

咱們都有一個計算機網絡的常識:不一樣的進程 不能使用同一端口

若是一個端口正在被使用,不管是TIME_WAIT、CLOSE_WAIT、仍是ESTABLISHED狀態。 這個端口都不能被複用,這裏面天然也是包括不能被用來LISTEN(監聽)。

但這件事也不是絕對的,以前跟你們講進程的建立過程提到過一件事: 當進程調用fork(2)系統調用的時候,會發生一系列資源的複製,其中就包括句柄。 因此,在調用fork(2)以前,打開任何文件,監聽端口產生的句柄也將會被複制。

經過這種方式,咱們就能夠達成"多進程端口監聽"。

 

咱們大名鼎鼎的 Nginx就是經過這種手法讓多個進程同時監聽在HTTP的服務端口上的, 這麼作的好處就在於,當外部請求到達,Linux內核會保證多個進程只 會有一個accept(2) 成功,這種狀況下此端口的服務可用性就和單個進程存在與否無關。 Nginx正是利用這一點達成「 不停服務reload、restart」的。


SO_REUSEADDR

有一個問題就是

爲何有時候重啓Apache會失敗,報「Address already in use」?

當時答得不太好,不太明白這個問題的關鍵點在哪裏,後來逐漸明白了。

TCP的原理會致使這樣的一個結果:

主動close socket的一方會進入TIME_WAIT,這個情況持續的時間取決於三件事

  • TCP關閉鏈接的五次揮手包何時到達
  • SO_LINGER的設置
  • /proc/sys/net/ipv4/tcp_tw_recycle 和 /proc/sys/net/ipv4/tcp_tw_reuse 的設置

總之默認狀況下,處於TIME_WAIT狀態的端口是不能用來LISTEN的。 這就致使,Apache重啓時產生80端口TIME_WAIT,進而致使Apache再次嘗試LISTEN失敗。


在不少開源代碼裏咱們會看到以下代碼:

int reuseaddr = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)); 

有了上面這段神奇的代碼,就不會出現上面的慘劇。但SO_REUSEADDR的做用不只限於上述。

Linux 的 SO_REUSEADDR 設置爲 1 有四種效果

  1. 當端口處在TIME_WAIT時候,能夠複用監聽。

  2. 能夠容許多個進程監聽同一端口,可是必須不一樣IP。

    這裏說的比較隱晦,若是進程A監聽0.0.0.0:80,B進程能夠成功監聽127.0.0.1:80, 順序反過來也是能夠的。

  3. 容許單個進程綁定相同的端口到多個socket上,但每一個socket綁定的IP地址不一樣。

  4. 使用UDP時候,能夠容許多個實例或者單進程同時監聽同個端口同個IP。

 

 

第七篇 CAP

https://zhuanlan.zhihu.com/p/20399316?refer=auxten
 筆記見這篇:
http://www.cnblogs.com/charlesblc/p/6341505.html
 
 

第八篇 sendfile

http://www.cnblogs.com/charlesblc/p/6341605.html
相關文章
相關標籤/搜索