定義:node
在電的系統中,由若干元件組成的用來使電信號按必定要求傳輸的電路或這種電路的部分,叫網絡。python
做爲一名從事過TMN開發的通訊專業畢業生,執拗地認爲網絡是從通訊系統中誕生的。通訊是人與人之間經過某種媒介進行的信息交流與傳遞。傳統的通訊網絡(即電話網絡)是由傳輸、交換和終端三大部分組成,通訊網絡是指將各個孤立的設備進行物理鏈接,實現信息交換的鏈路,從而達到資源共享和通訊的目的。通訊網絡能夠從覆蓋範圍,拓撲結構,交換方式等諸多視角進行分類…… 滿滿的回憶,仍是留在書架上吧。web
網絡的概念外延被不斷的放大着,抽象的思惟能力是人們創新乃至創造的根源。網絡用來表示諸多對象及其相互聯繫,數學上的圖,物理學上的模型,交通網絡,人際網絡,城市網絡等等,總之,網絡被總結成從同類問題中抽象出來用數學中的圖論科學來表達並研究的一種模型。算法
不少夥伴認爲,瞭解這些以後呢,然並卵。咱們關心的只是計算機網絡,算機網絡是用通訊線路和設備將分佈在不一樣地點的多臺計算機系統互相鏈接起來,按照網絡協議,分享軟硬件功能,最終實現資源共享的系統。特別的,咱們談到的網絡只是互聯網——Internet,或者移動互聯網,須要的是寫互連網應用程序。可是,一位工做了五六年的編程高手曾對我說,如今終於瞭解到基礎知識有多重要,技術在不斷演進,而相對不變的就是那些原理和編程模型了。編程
老碼農深覺得然,編程實踐就是從具體到抽象,再到具體,循環往復,螺旋式上升的過程。瞭解前世此生,只是爲了可能觸摸到「勢」。基礎越紮實,建築就會越有想象的空間。 對於網絡編程的基礎,大概要從OSI的七層協議模型開始了。設計模式
七層模型(OSI,Open System Interconnection參考模型),是參考是國際標準化組織制定的一個用於計算機或通訊系統間互聯的標準體系。它是一個七層抽象的模型,不只包括一系列抽象的術語和概念,也包括具體的協議。 經典的描述以下:數組
簡述每一層的含義:安全
物理層(Physical Layer):創建、維護、斷開物理鏈接。服務器
數據鏈路層 (Link):邏輯鏈接、進行硬件地址尋址、差錯校驗等。網絡
網絡層 (Network):進行邏輯尋址,實現不一樣網絡之間的路徑選擇。
傳輸層 (Transport):定義傳輸數據的協議端口號,及流控和差錯校驗。
會話層(Session Layer):創建、管理、終止會話。
表示層(Presentation Layer):數據的表示、安全、壓縮。
應用層 (Application):網絡服務與最終用戶的一個接口
每一層利用下一層提供的服務與對等層通訊,每一層使用本身的協議。瞭解了這些,然並卵。可是,這一模型確實是絕大多數網絡編程的基礎,做爲抽象類存在的,而TCP/IP協議棧只是這一模型的一個具體實現。
TCP/IP是Internet的基礎,是一組協議的代名詞,包括許多協議,組成了TCP/IP協議棧。TCP/IP 有四層模型和五層模型之說,區別在於數據鏈路層是否做爲獨立的一層存在。我的傾向於5層模型,這樣2層和3層的交換設備更容易弄明白。當談到網絡的2層或3層交換機的時候,就知道指的是那些協議。
數據是如何傳遞呢?這就要了解網絡層和傳輸層的協議,咱們熟知的IP包結構是這樣的:
IP協議和IP地址是兩個不一樣的概念,這裏沒有涉及IPV6的。不關注網絡安全的話,對這些結構沒必要耳熟能詳的。傳輸層使用這樣的數據包進行傳輸,傳輸層又分爲面向鏈接的可靠傳輸TCP和數據報UDP。TCP的包結構:
TCP 鏈接創建的三次握手確定是必知必會,在系統調優的時候,內核中關於網絡的相關參數與這個圖息息相關。UDP是一種無鏈接的傳輸層協議,提供的是簡單不可靠的信息傳輸。協議結構相對簡單,包括源和目標的端口號,長度以及校驗和。基於TCP和UDP的數據封裝及解析示例以下:
仍是然並卵麼?一個數據包的大小了解了,會發現什麼?PayLoad究竟是多少?在設計協議通訊的時候,這些都爲咱們提供了粒度定義的依據。進一步,經過一個例子看看吧。
FTP是一個比較好的例子。爲了方便起見,假設兩條計算機分別是A 和 B,將使用FTP 將A上的一個文件X傳輸到B上。
首先,計算機A和B之間要有物理層的鏈接,能夠是有線好比同軸電纜或者雙絞線經過RJ-45的電路接口鏈接,也能夠是無線鏈接例如WIFI。先簡化一下,考慮局域網,暫不討論路由器和交換機以及WIFI熱點。這些物理層的鏈接創建了比特流的原始傳輸通路。
接下來,數據鏈路層登場,創建兩臺計算機的數據鏈路。若是A和B所在的網絡上同時鏈接着計算機C,D,E等等,A和B之間如何創建的數據鏈路呢?這一過程就是物理尋址,A要在衆多的物理鏈接中找到B,依賴的是計算機的物理地址即MAC地址,對就是網卡上的MAC地址。以太網採用CSMA/CD方式來傳輸數據,數據在以太網的局域網中都是以廣播方式傳輸的,整個局域網中的全部節點都會收到該幀,只有目標MAC地址與本身的MAC地址相同的幀纔會被接收。A經過差錯控制和接入控制找到了B的網卡,創建可靠的數據通路。
那IP地址呢? 數據鏈路創建起來了,還須要IP地址麼?咱們FTP 命令中制定的是IP地址而不是MAC地址呀?IP地址是邏輯地址,包括網絡地址和主機地址。若是A和B在不一樣的局域網中,中間有着多個路由器,A須要對B進行邏輯尋址才能夠的。物理地址用於底層的硬件的通訊,邏輯地址用於上層的協議間的通訊。在以太網中:邏輯地址就是IP地址,物理地址就是MAC 地址。在使用中,兩種地址是用必定的算法將他們兩個聯繫起來的。因此,IP是用來在網絡上選擇路由的,在FTP的命令中,IP中的原地址就是A的IP地址,目標地址就是B的IP地址。這應該就是網絡層,負責將分組數據從源端傳輸到目的端。
A向B傳輸一個文件時,若是文件中有部分數據丟失,就可能會形成在B上沒法正常閱讀或使用。因此須要一個可靠的鏈接,可以確保傳輸過程的完整性,這就是傳輸層的TCP協議,FTP就是創建在TCP之上的。TCP的三次握手肯定了雙方數據包的序號、最大接受數據的大小(window)以及MSS(Maximum Segment Size)。TCP利用IP完成尋址,TCP中的提供了端口號,FTP中目的端口號通常是21。傳輸層的端口號對應主機進程,指本地主機與遠程主機正在進行的會話。
會話層用來創建、維護、管理應用程序之間的會話,主要功能是對話控制和同步,編程中所涉及的session是會話層的具體體現。表示層完成數據的解編碼,加解密,壓縮解壓縮等,例如FTP中bin命令,表明了二進制傳輸,即所傳輸層數據的格式。
HTTP協議裏body中的Json,XML等均可以認爲是表示層。應用層就是具體應用的自己了,FTP中的PUT,GET等命令都是應用的具體功能特性。
簡單地,物理層到電纜鏈接,數據鏈路層到網卡,網絡層路由到主機,傳輸層到端口,會話層維持會話,表示層表達數據格式,應用層就是具體FTP中的各類命令功能了。
瞭解了7層模型就能夠編程了麼,拿起編程語言就能夠耍了麼?剛開始上手嘗試仍是能夠的,若是要進一步,老碼農以爲仍是看看底層實現的好,由於一切歸根到底都會歸結爲系統調用。到了操做系統層面如何看網絡呢?Socket登場了。
在Linux世界,「一切皆文件」,操做系統把網絡讀寫做爲IO操做,就像讀寫文件那樣,對外提供出來的編程接口就是Socket。因此,socket(套接字)是通訊的基石,是支持TCP/IP協議網絡通訊的基本操做單元。socket實質上提供了進程通訊的端點。進程通訊以前,雙方首先必須各自建立一個端點,不然是沒有辦法創建聯繫並相互通訊的。一個完整的socket有一個本地惟一的socket號,這是由操做系統分配的。
從設計模式的角度看, Socket實際上是一個外觀模式,它把複雜的TCP/IP協議棧隱藏在Socket接口後面,對用戶來講,一組簡單的Socket接口就是所有。當應用程序建立一個socket時,操做系統就返回一個整數做爲描述符(descriptor)來標識這個套接字。而後,應用程序以該描述符爲傳遞參數,經過調用函數來完成某種操做(例如經過網絡傳送數據或接收輸入的數據)。以TCP 爲例,典型的Socket 使用以下:
在許多操做系統中,Socket描述符和其餘I/O描述符是集成在一塊兒的,操做系統把socket描述符實現爲一個指針數組,這些指針指向內部數據結構。進一步看,操做系統爲每一個運行的進程維護一張單獨的文件描述符表。當進程打開一個文件時,系統把一個指向此文件內部數據結構的指針寫入文件描述符表,並把該表的索引值返回給調用者 。
既然Socket和操做系統的IO操做相關,那麼各操做系統IO實現上的差別會致使Socket編程上的些許不一樣。看看我Mac上的Socket.so 會發現和CentOS上的仍是些不一樣的。
進程進行Socket操做時,也有着多種處理方式,如阻塞式IO,非阻塞式IO,多路複用(select/poll/epoll),AIO等等。
多路複用每每在提高性能方面有着重要的做用。select系統調用的功能是對多個文件描述符進行監視,當有文件描述符的文件讀寫操做完成以及發生異常或者超時,該調用會返回這些文件描述符。select 須要遍歷全部的文件描述符,就遍歷操做而言,複雜度是 O(N)。
epoll相關係統調用是在Linux 2.5 後的某個版本開始引入的。該系統調用針對傳統的select/poll不足,設計上做了很大的改動。select/poll 的缺點在於:
每次調用時要重複地從用戶模式讀入參數,並重復地掃描文件描述符。
每次在調用開始時,要把當前進程放入各個文件描述符的等待隊列。在調用結束後,又把進程從各個等待隊列中刪除。
epoll 是把 select/poll 單個的操做拆分爲 1 個 epoll_create,多個 epoll_ctrl和一個 wait。此外,操做系統內核針對 epoll 操做添加了一個文件系統,每個或者多個要監視的文件描述符都有一個對應的inode 節點,主要信息保存在 eventpoll 結構中。而被監視的文件的重要信息則保存在 epitem 結構中,是一對多的關係。因爲在執行 epoll_create 和 epoll_ctrl 時,已經把用戶模式的信息保存到內核了, 因此以後即使反覆地調用 epoll_wait,也不會重複地拷貝參數,不會重複掃描文件描述符,也不反覆地把當前進程放入/拿出等待隊列。
因此,當前主流的Server側Socket實現大都採用了epoll的方式,例如Nginx, 在配置文件能夠顯式地看到 use epoll。
瞭解了7層協議模型和操做系統層面的Socket實現,能夠方便咱們理解網絡編程。
在系統架構的時候,有重要的一環就是拓撲架構,這裏涉及了網絡等基礎設施,那麼7層協議下四層就會有助於咱們對業務系統網絡結構的觀察和判斷。在系統設計的時候,每每採用面向接口的設計,而接口也每每是基於HTTP協議的Restful API。 那接口的粒度就能夠將data segment做爲一個約束了,同時能夠關注到移動互聯網中的弱網環境。
不一樣的編程語言,有着不一樣的框架和庫,真正的編寫網絡程序代碼並不複雜,例如,用Erlang 中 gen_tcp 用於編寫一個簡單的Echo服務器:
然而,寫出漂亮的服務器程序仍然是一件很是吃功夫的事情,例如,我的很是喜歡的python Tornado 代碼, 在ioloop.py 中有對多路複用的選擇:
在HTTPServer.py 中一樣繼承了TCPServer,進而實現了HTTP協議,代碼片斷以下:
或許,老碼農說的都是錯的,瞭解了所謂的網絡基礎,也不必定寫出漂亮的代碼,不瞭解所謂的網絡基礎,也不必定寫不出漂亮的代碼,全當他自言自語吧。