day 26

day 26

1. 軟件開發架構

1.1 C/S架構

客戶端與服務器端架構,這種架構也是從用戶層面(也能夠是物理層面)來劃分的。python

這裏的客戶端通常泛指客戶端應用程序EXE,程序須要先安裝後,才能運行在用戶的電腦上,對用戶的電腦操做系統環境依賴較大。編程

CS架構

C: Client (客戶端)設計模式

S: Server (服務端)瀏覽器

優勢:緩存

  1. 客戶端由於是獨立設計,因此能夠實現個性化。
  2. 由於客戶端是須要進行安裝的,能夠不須要重複安裝和加載。
  3. 由於客戶端是獨立開發的,因此有能力對客戶端進行安全設計。

缺點:安全

  1. 由於客戶端是不須要重複安裝,因此用戶能夠不更新與升級,增長了維護成本。
  2. 由於須要開發客戶端和服務器兩套程序,因此開發成本會增長 。
  3. 兼容性差,若是遇到不一樣的操做系統,須要爲不一樣的操做系統各開發一套客戶端。

1.2 B/S架構

瀏覽器端與服務器端架構,這種架構是從用戶層面來劃分的。服務器

Browser瀏覽器,其實也是一種Client客戶端,只是這個客戶端不須要你們去安裝什麼應用程序,只需在瀏覽器上經過HTTP請求服務器端相關的資源(網頁資源),客戶端Browser瀏覽器就能進行增刪改查。網絡

BS架構

B: Browser ( 瀏覽器端 )架構

S: Server (服務端)併發

優勢:

  1. 由於B/S架構具有通用性,因此開發成本較低。
  2. 由於不須要安裝客戶端,因此客戶端不須要進行升級,只須要更新後臺代碼便可實現全部客戶端的更新。
  3. 由於B/S架構多用WEB網頁進行開發,因此增、刪功能也很是容易,只須要修改網頁便可完成。

缺點:

  1. 耗流量,每次都要加載所有的內容(不過有緩存能夠下降流量損耗)。
  2. 由於沒有獨立的客戶端,因此沒法實現個性化(經過帳號體系能夠實現)。
  3. 由於沒有獨立設計客戶端,因此客戶端難以實現安全控制(HTTPS、控件)。
  4. 難以實現特殊的操做(刪本地文件),因此全部的殺毒軟件都是C/S架構的。

總結:

CS架構響應速度快,安全性強,通常應用於局域網中,可是開發維護成本高;BS能夠實現跨平臺,客戶端零維護,可是個性化能力低,響應速度較慢。

問題:數據放在服務端和客戶端的利與弊?

  • 服務端統一處理有更好的安全性和穩定性並且升級比較容易,不過服務器負擔就增長了。
  • 客戶端將負擔分配到每一個用戶,從而能夠節約服務器資源,安全性和穩定性可能會有必定的問題,可是升級比較麻煩,每一個安裝的客戶端程序都須要升級,另外爲了節省網絡資源,經過網絡傳輸的數據應該儘可能減小!

2. 網絡編程基礎

2.1 以太網:局域網與交換機

局域網與交換機

2.1.1 以太網協議

對電信號來作分組。之前每一個公司都有本身的分組方式,後來造成了統一的標準,即以太網協議ethernet。

ethernet規定:一組電信號構成一個數據報,叫作'幀',每一數據幀分紅:報頭head和數據data兩部分

  • head包含:(固定18個字節)
    • 發送者/源地址,6個字節
    • 接收者/目標地址,6個字節
    • 數據類型,6個字節
  • data包含:(最短46字節,最長1500字節)
- -
head data
  • 數據報的具體內容:head長度+data長度=最短64字節,最長1518字節,超過最大限制就分片發送

2.1.2 Mac地址

​ head中包含的源和目標地址由來:ethernet規定接入internet的設備都必須具有網卡,發送端和接收端的地址即是指網卡的地址,即mac地址。

  mac地址:每塊網卡出廠時都被燒製上一個世界惟一的mac地址,長度爲48位2進制,一般由12位16進制數表示(前六位是廠商編號,後六位是流水線號)

Mac地址

2.2 廣播

主機之間「一對全部」的通信模式,網絡對其中每一臺主機發出的信號都進行無條件複製並轉發,全部主機均可以接收到全部信息(無論你是否須要),因爲其不用路徑選擇,因此其網絡成本能夠很低廉。有線電視網就是典型的廣播型網絡,咱們的電視機其實是接受到全部頻道的信號,但只將一個頻道的信號還原成畫面。在數據網絡中也容許廣播的存在,但其被限制在二層交換機的局域網範圍內,禁止廣播數據穿過路由器,防止廣播數據影響大面積的主機。

2.3 ip地址與ip協議

  • 規定網絡地址的協議叫ip協議,它定義的地址稱之爲ip地址,普遍採用的v4版本即ipv4,它規定網絡地址由32位2進製表示
  • 範圍0.0.0.0-255.255.255.255
  • 一個ip地址一般寫成四段十進制數,例:172.16.10.1

2.4 arp協議 ——經過IP地址去找MAC地址

  地址解析協議,即ARP(Address Resolution Protocol),是根據IP地址獲取物理地址的一個TCP/IP協議。

  主機發送信息時將包含目標IP地址的ARP請求廣播到網絡上的全部主機,並接收返回消息,以此肯定目標的物理地址。

2.5 廣域網與路由器

廣域網與路由器

2.6 路由器

  路由器(Router),是鏈接因特網中各局域網、廣域網的設備,它會根據信道的狀況自動選擇和設定路由,以最佳路徑,按先後順序發送信號。 路由器是互聯網絡的樞紐,"交通警察"。目前路由器已經普遍應用於各行各業,各類不一樣檔次的產品已成爲實現各類骨幹網內部鏈接、骨幹網間互聯和骨幹網與互聯網互聯互通業務的主力軍。路由和交換機之間的主要區別就是交換機發生在OSI參考模型第二層(數據鏈路層),而路由發生在第三層,即網絡層。這一區別決定了路由和交換機在移動信息的過程當中需使用不一樣的控制信息,因此說二者實現各自功能的方式是不一樣的。

路由器(Router)又稱網關設備(Gateway)是用於鏈接多個邏輯上分開的網絡,所謂邏輯網絡是表明一個單獨的網絡或者一個子網。當數據從一個子網傳輸到另外一個子網時,可經過路由器的路由功能來完成。所以,路由器具備判斷網絡地址和選擇IP路徑的功能,它能在多網絡互聯環境中,創建靈活的鏈接,可用徹底不一樣的數據分組和介質訪問方法鏈接各類子網,路由器只接受源站或其餘路由器的信息,屬網絡層的一種互聯設備。  

2.7 局域網

  局域網(Local Area Network,LAN)是指在某一區域內由多臺計算機互聯成的計算機組。通常是方圓幾公里之內。局域網能夠實現文件管理、應用軟件共享、打印機共享、工做組內的日程安排、電子郵件和傳真通訊服務等功能。局域網是封閉型的,能夠由辦公室內的兩臺計算機組成,也能夠由一個公司內的上千臺計算機組成。  

2.8 子網掩碼

  所謂」子網掩碼」,就是表示子網絡特徵的一個參數。它在形式上等同於IP地址,也是一個32位二進制數字,它的網絡部分所有爲1,主機部分所有爲0。好比,IP地址172.16.10.1,若是已知網絡部分是前24位,主機部分是後8位,那麼子網絡掩碼就是11111111.11111111.11111111.00000000,寫成十進制就是255.255.255.0。

  知道」子網掩碼」,咱們就能判斷,任意兩個IP地址是否處在同一個子網絡。方法是將兩個IP地址與子網掩碼分別進行AND運算(兩個數位都爲1,運算結果爲1,不然爲0),而後比較結果是否相同,若是是的話,就代表它們在同一個子網絡中,不然就不是。

好比,已知IP地址172.16.10.1和172.16.10.2的子網掩碼都是255.255.255.0,請問它們是否在同一個子網絡?二者與子網掩碼分別進行AND運算,

172.16.10.1:10101100.00010000.00001010.000000001
255255.255.255.0:11111111.11111111.11111111.00000000
AND運算得網絡地址結果:10101100.00010000.00001010.000000001->172.16.10.0

 

172.16.10.2:10101100.00010000.00001010.000000010
255255.255.255.0:11111111.11111111.11111111.00000000
AND運算得網絡地址結果:10101100.00010000.00001010.000000001->172.16.10.0
結果都是172.16.10.0,所以它們在同一個子網絡

2.9 端口

咱們知道,一臺擁有IP地址的主機能夠提供許多服務,好比Web服務、FTP服務、SMTP服務等,這些服務徹底能夠經過1個IP地址來實現。那麼,主機是怎樣區分不一樣的網絡服務呢?顯然不能只靠IP地址,由於IP地址與網絡服務的關係是一對多的關係。其實是經過「IP地址+端口號」來區分不一樣的服務的。

3 OSI模型

人們按照分工不一樣把互聯網協議從邏輯上劃分了層級:(通常做爲開發人員,掌握應傳網數物 五層便可):

OSI模型

每層運行常見物理設備:

每層常見的物理設備

每層運行常見的協議:

每層常見的協議

3.1 物理層

物理層鏈接

  • 構成

    網絡通訊的數據傳輸介質,由鏈接不一樣結點的電纜與設備共同構成。

  • 功能:

    基於電器特性發送高低電壓(電信號),高電壓對應數字1,低電壓對應數字0。

3.2 數據鏈路層

  • 由來

    單純的電信號0和1沒有任何意義,必須規定電信號多少位一組,每組什麼意思。

  • 功能

    基於以太網協議,定義了電信號的分組方式。

3.3 網絡層

  • 功能

    引入一套新的地址用來區分不一樣的廣播域/子網,這套地址即網絡地址

  • 由來

    有了ethernet、Mac地址、廣播的發送方式,世界上的計算機就能夠彼此通訊了,問題是世界範圍的互聯網是由 一個個彼此隔離的小的局域網組成的,那麼若是全部的通訊都採用以太網的廣播方式,那麼一臺機器發送的包全世界都會收到。

    廣播

3.3.1 IP協議

用於標識惟一的一臺計算機(局域網)的地址。

  • IP協議的做用
    • 爲每一臺計算機分配IP地址
    • 肯定哪些地址在同一個子網絡

3.3.2 arp協議

  • 由來

    通訊是基於Mac的廣播方式實現,計算機在發包時,獲取自身的Mac是容易的,如何獲取目標主機的Mac,就須要經過arp協議

  • 功能

    廣播的方式發送數據包, 全部主機接收後拆開包,發現目標IP爲本身的,就響應,返回本身的Mac。

3.4 傳輸層

  • 功能

    創建端口到端口的通訊

  • 由來

    網絡層的IP幫咱們區分子網,以太網層的Mac幫咱們找到主機,而後你們使用的都是應用程序,你的電腦上可能同時開啓qq,暴風影音,等多個應用程序。

    那麼咱們經過IP和Mac找到了一臺特定的主機,如何標識這臺主機上的應用程序,答案就是端口,端口即應用程序與網卡關聯的編號。

    有了Mac地址+IP地址+端口,咱們就能肯定世界上獨一無二的一臺計算機上的應用程序。

3.4.1 TCP協議

​ 可靠傳輸,TCP數據包沒有長度限制,理論上能夠無限長,可是爲了保證網絡的效率,一般TCP數據包的長度不會超過IP數據包的長度,以確保單個TCP數據包沒必要再分割。

- - - -
以太網頭 IP頭 TCP頭 數據

3.4.2 UDP協議

不可靠傳輸,」報頭」部分一共只有8個字節,總長度不超過65,535字節,正好放進一個IP數據包。
- - - -
以太網頭 IP頭 UDP頭 數據

3.5 應用層

  • 功能

    規定應用程序的數據格式。

  • 由來

    用戶使用的都是應用程序,均工做於應用層,互聯網是開發的,你們均可以開發本身的應用程序,數據多種多樣,必須規定好數據的組織形式 。

4 傳輸控制協議

  • TCP協議:

    提供面向鏈接的服務,在傳送數據以前必須先創建鏈接,數據傳送完成後要釋放鏈接。所以TCP是一種可靠的的運輸服務,可是正由於這樣,不可避免的增長了許多的開銷,好比確認,流量控制等。對應的應用層的協議主要有 SMTP,TELNET,HTTP,FTP 等。

  • UDP協議:

    在傳送數據前不須要先創建鏈接,遠地的主機在收到UDP報文後也不須要給出任何確認。雖然UDP不提供可靠交付,可是正是由於這樣,省去和不少的開銷,使得它的速度比較快,好比一些對實時性要求較高的服務,就經常使用的是UDP。對應的應用層的協議主要有 DNS,TFTP,DHCP,SNMP,NFS 等。

  • 經常使用的端口號

    操做系統中,通常0-1024的端口都被默認使用了(0-1024不要動),儘可能使用8000以後的端口號。

    應用程序 FTP TFTP TELNET SMTP DNS HTTP SSH MYSQL
    熟知端口 21,20 69 23 25 53 80 22 3306
    傳輸層協議 TCP UDP TCP TCP UDP TCP TCP TCP

4.1 TCP協議

4.1.1 TCP創建鏈接(三次握手)

三次握手

  • 最開始的時候客戶端和服務器都是處於CLOSED狀態。主動打開鏈接的爲客戶端,被動打開鏈接的是服務器。
  1. TCP服務器進程先建立傳輸控制塊TCB,時刻準備接受客戶進程的鏈接請求,此時服務器就進入了LISTEN(監聽)狀態;
  2. TCP客戶進程也是先建立傳輸控制塊TCB,而後向服務器發出鏈接請求報文,這是報文首部中的同部位SYN=1,同時選擇一個初始序列號 seq=x ,此時,TCP客戶端進程進入了 SYN-SENT(同步已發送狀態)狀態。TCP規定,SYN報文段(SYN=1的報文段)不能攜帶數據,但須要消耗掉一個序號。
  3. TCP服務器收到請求報文後,若是贊成鏈接,則發出確認報文。確認報文中應該 ACK=1,SYN=1,確認號是ack=x+1,同時也要爲本身初始化一個序列號 seq=y,此時,TCP服務器進程進入了SYN-RCVD(同步收到)狀態。這個報文也不能攜帶數據,可是一樣要消耗一個序號。
  4. TCP客戶進程收到確認後,還要向服務器給出確認。確認報文的ACK=1,ack=y+1,本身的序列號seq=x+1,此時,TCP鏈接創建,客戶端進入ESTABLISHED(已創建鏈接)狀態。TCP規定,ACK報文段能夠攜帶數據,可是若是不攜帶數據則不消耗序號。
  5. 當服務器收到客戶端的確認後也進入ESTABLISHED狀態,此後雙方就能夠開始通訊了。

4.1.2 TCP斷開鏈接(四次揮手)

四次揮手

  • 數據傳輸完畢後,雙方均可釋放鏈接。最開始的時候,客戶端和服務器都是處於ESTABLISHED狀態,而後客戶端主動關閉,服務器被動關閉。
  1. 客戶端進程發出鏈接釋放報文,而且中止發送數據。釋放數據報文首部,FIN=1,其序列號爲seq=u(等於前面已經傳送過來的數據的最後一個字節的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態。 TCP規定,FIN報文段即便不攜帶數據,也要消耗一個序號。
  2. 服務器收到鏈接釋放報文,發出確認報文,ACK=1,ack=u+1,而且帶上本身的序列號seq=v,此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態。TCP服務器通知高層的應用進程,客戶端向服務器的方向就釋放了,這時候處於半關閉狀態,即客戶端已經沒有數據要發送了,可是服務器若發送數據,客戶端依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間。
  3. 客戶端收到服務器的確認請求後,此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送鏈接釋放報文(在這以前還須要接受服務器發送的最後的數據)。
  4. 服務器將最後的數據發送完畢後,就向客戶端發送鏈接釋放報文,FIN=1,ack=u+1,因爲在半關閉狀態,服務器極可能又發送了一些數據,假定此時的序列號爲seq=w,此時,服務器就進入了LAST-ACK(最後確認)狀態,等待客戶端的確認。
  5. 客戶端收到服務器的鏈接釋放報文後,必須發出確認,ACK=1,ack=w+1,而本身的序列號是seq=u+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態。注意此時TCP鏈接尚未釋放,必須通過2∗ *∗MSL(最長報文段壽命)的時間後,當客戶端撤銷相應的TCB後,才進入CLOSED狀態。
  6. 服務器只要收到了客戶端發出的確認,當即進入CLOSED狀態。一樣,撤銷TCB後,就結束了此次的TCP鏈接。能夠看到,服務器結束TCP鏈接的時間要比客戶端早一些。

4.3 TCP協議中的問題

【問題1】爲何鏈接的時候是三次握手,關閉的時候倒是四次握手?

答:由於當Server端收到Client端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。可是關閉鏈接時,當Server端收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四步握手。

【問題2】爲何TIME_WAIT狀態須要通過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?

答:雖然按道理,四個報文都發送完畢,咱們能夠直接進入CLOSE狀態了,可是咱們必須假象網絡是不可靠的,有能夠最後一個ACK丟失。因此TIME_WAIT狀態就是用來重發可能丟失的ACK報文。在Client發送出最後的ACK回覆,但該ACK可能丟失。Server若是沒有收到ACK,將不斷重複發送FIN片斷。因此Client不能當即關閉,它必須確認Server接收到了該ACK。Client會在發送出ACK以後進入到TIME_WAIT狀態。Client會設置一個計時器,等待2MSL的時間。若是在該時間內再次收到FIN,那麼Client會重發ACK並再次等待2MSL。所謂的2MSL是兩倍的MSL(Maximum Segment Lifetime)。MSL指一個片斷在網絡中最大的存活時間,2MSL就是一個發送和一個回覆所需的最大時間。若是直到2MSL,Client都沒有再次收到FIN,那麼Client推斷ACK已經被成功接收,則結束TCP鏈接。

【問題3】爲何不能用兩次握手進行鏈接?

答:3次握手完成兩個重要的功能,既要雙方作好發送數據的準備工做(雙方都知道彼此已準備好),也要容許雙方就初始序列號進行協商,這個序列號在握手過程當中被髮送和確認。如今把三次握手改爲僅須要兩次握手,死鎖是可能發生的。做爲例子,考慮計算機S和C之間的通訊,假定C給S發送一個鏈接請求分組,S收到了這個分組,併發 送了確認應答分組。按照兩次握手的協定,S認爲鏈接已經成功地創建了,能夠開始發送數據分組。但是,C在S的應答分組在傳輸中被丟失的狀況下,將不知道S 是否已準備好,不知道S創建什麼樣的序列號,C甚至懷疑S是否收到本身的鏈接請求分組。在這種狀況下,C認爲鏈接還未創建成功,將忽略S發來的任何數據分 組,只等待鏈接確認應答分組。而S在發出的分組超時後,重複發送一樣的分組。這樣就造成了死鎖。

【問題4】若是已經創建了鏈接,可是客戶端忽然出現故障了怎麼辦?

TCP還設有一個保活計時器,顯然,客戶端若是出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求後都會從新復位這個計時器,時間一般是設置爲2小時,若兩小時尚未收到客戶端的任何數據,服務器就會發送一個探測報文段,之後每隔75秒鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着就關閉鏈接。

5 Socket套接字

5.1 什麼是Socket

Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來講,一組簡單的接口就是所有,讓Socket去組織數據,以符合指定的協議。

因此,咱們無需深刻理解tcp/udp協議,socket已經爲咱們封裝好了,咱們只須要遵循socket的規定去編程,寫出的程序天然就是遵循tcp/udp標準的。

5.2 套接字工做流程

socket流程

服務器端先初始化Socket,而後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端鏈接。在這時若是有個客戶端初始化一個Socket,而後鏈接服務器(connect),若是鏈接成功,這時客戶端與服務器端的鏈接就創建了。客戶端發送數據請求,服務器端接收請求並處理請求,而後把迴應數據發送給客戶端,客戶端讀取數據,最後關閉鏈接,一次交互結束。

5.3 基於TCP協議的套接字編程

5.3.1 一次性通訊

# File-服務端.py
import socket

phone = socket.socket(socket.AF_INET,
                      socket.SOCK_STREAM)  #tcp稱爲流式協議,udp稱爲數據報協議SOCK_DGRAM

# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1', 8081))

phone.listen(5)  # 半鏈接池,限制的是請求數

print('start....')
conn, client_addr = phone.accept()  #(三次握手創建的雙向鏈接,(客戶端的ip,端口))
print(conn)
print(client_addr)

#五、通訊:收\發消息
data = conn.recv(1024)  #最大接收的字節數
print('來自客戶端的數據', data)
conn.send(data.upper())

#六、斷開鏈接
conn.close()

#七、結束服務
phone.close()
# File-客戶端.py
import socket

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(phone)

phone.connect(('127.0.0.1', 8081))  # 指定鏈接服務端ip和端口

#三、通訊:發\收消息
phone.send('hello'.encode('utf-8'))
# phone.send(bytes('hello',encoding='utf-8'))
data = phone.recv(1024)
print(data)

#四、關閉
phone.close()

5.3.2 循環通訊

# File-服務端.py
import socket

phone = socket.socket(socket.AF_INET,
                      socket.SOCK_STREAM)  #tcp稱爲流式協議,udp稱爲數據報協議SOCK_DGRAM

# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1', 8080))

phone.listen(5)  # 半鏈接池,限制的是請求數

print('start....')
while True:  # 鏈接循環
    conn, client_addr = phone.accept()  #(三次握手創建的雙向鏈接,(客戶端的ip,端口))
    # print(conn)
    print('已經有一個鏈接創建成功', client_addr)

    #五、通訊:收\發消息
    while True:  # 通訊循環
        try:
            print('服務端正在收數據...')
            data = conn.recv(1024)  #最大接收的字節數,沒有數據會在原地一直等待收,即發送者發送的數據量必須>0bytes
            # print('===>')
            if len(data) == 0: break  #在客戶端單方面斷開鏈接,服務端纔會出現收空數據的狀況
            print('來自客戶端的數據', data)
            conn.send(data.upper())
        except ConnectionResetError:
            break
    #六、斷開鏈接
    conn.close()

#七、中止服務
phone.close()
# File-客戶端.py
import socket

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

phone.connect(('127.0.0.1', 8080))  # 指定鏈接服務端ip和端口

#三、通訊:發\收消息
while True:  # 通訊循環
    msg = input('>>: ').strip()  #msg=''
    if len(msg) == 0: continue
    phone.send(msg.encode('utf-8'))
    # print('has send----->')
    data = phone.recv(1024)
    # print('has recv----->')
    print(data)

#四、斷開鏈接
phone.close()
相關文章
相關標籤/搜索