python-day31(正式學習)

1、單機架構python

應用領域:linux

  • 植物大戰殭屍
  • office

2、CS架構面試

149-網絡架構及其演變過程-cs架構.jpg?x-oss-process=style/watermark

應用領域:數據庫

  • QQ
  • 大型網絡遊戲

計算機發展初期用戶去取數據,直接就去主機拿,從這裏開始就分出了客戶端和服務端。編程

客戶端:用戶安裝的軟件;設計模式

服務端:統一管理數據庫的主機中的軟件就叫作服務端,再後來服務端不僅是管理數據,外加處理業務邏輯。瀏覽器

2.1 CS架構要求緩存

  1. 用戶操做系統安裝客戶端;產商操做系統部署服務端
  2. 每一個用戶須要獨立安裝軟件、服務端升級也要每一個用戶升級

2.2 面試題:數據放在服務端和客戶端的利與弊?安全

答:服務器

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

3、BS架構

149-網絡架構及其演變過程-bs架構.jpg?x-oss-process=style/watermark

應用領域:

  • 淘寶
  • 京東

統一客戶端即默認安裝用戶電腦中的瀏覽器,訪問同種類的網站,具體業務的處理根據相應協議和標準提供通用的服務器程序,在不一樣的服務器處理。

3.1 兩種BS架構

149-網絡架構及其演變過程-osi和tcp.jpg?x-oss-process=style/watermark

OSI主要用於教學(萬惡的大學、綠本的計算機書),咱們在編程的時候用的都是TCP/IP。

TCP/IP的對應關係,就像咱們在淘寶購物,所在位置有的快遞(網絡接入層),告訴賣家地址(網絡互聯層)、快遞送貨(運輸層)、收到貨物拆包使用(應用層)。

注意:對於普遍使用的東西就須要制定相應的標準,就像大公司有不少制度來規範作事情的流程。因爲網絡傳輸應用很是普遍,可是規矩不是強制性的,因此叫作協議而不是標準,TCP/IP參考模型也能夠看作是一種協議。BS結構中TCP/IP模型中的網絡接入層沒有響應的協議,網絡互聯層是IP協議,傳輸層是TCP協議,應用層是HTTP協議,另外仍是用到了DNS結構,並且在HTTP上層還有相應。

基於BS結構下的程序就要求解決速度問題,而速度問題的核心就是解決海量數據操做和高併發問題,網站複雜架構就是從這兩個問題演變出來的。

4、CS架構和BS架構區別

149-網絡架構及其演變過程-csbs區別.jpg?x-oss-process=style/watermark

互聯網的本質就是一系列的網絡協議,這個協議就叫OSI協議(一系列協議),按照功能不一樣,分工不一樣,人爲的分層七層。實際上這個七層是不存在的。沒有這七層的概念,只是人爲的劃分而已。區分出來的目的只是讓你明白哪一層是幹什麼用的。

每一層都運行不一樣的協議。協議是幹什麼的,協議就是標準。

實際上還有人把它劃成五層、四層。

七層劃分爲:應用層、表示層、會話層、傳輸層、網絡層、數據鏈路層、物理層。

五層劃分爲:應用層、傳輸層、網絡層、數據鏈路層、物理層。

四層劃分爲:應用層、傳輸層、網絡層、網絡接口層。

151-大白話OSI七層協議-七層協議.jpg?x-oss-process=style/watermark

每層運行常見的物理設備

151-大白話OSI七層協議-物理設備.jpg?x-oss-process=style/watermark

1、物理層

物理層功能:主要是基於電器特性發送高低電壓(電信號),高電壓對應數字1,低電壓對應數字0

物理層字面意思解釋:物理傳輸、硬件、物理特性。在深圳的你與北京的朋友聊天,你的電腦必需要能上網,物理體現是什麼?是否是接一根網線,插個路由器,北京的朋友那邊是否是也有根網線,也得插個路由器。也就是說計算機與計算機之間的通訊,必需要有底層物理層方面的連通,就相似於你打電話,中間是否是必須得連電話線。

中間的物理連接能夠是光纜、電纜、雙絞線、無線電波。中間傳的是電信號,即010101...這些二進制位。

151-大白話OSI七層協議-物理層.jpg?x-oss-process=style/watermark

底層傳輸的010010101001...這些二進制位怎麼才能讓它有意義呢?

151-大白話OSI七層協議-物理層1.jpg?x-oss-process=style/watermark

要讓這些010010101001...有意思,人爲的分組再適合不過了,8位一組,發送及接收都按照8位一組來劃分。接收到8位爲一組的話,那麼就能夠按照這8位數來作運算。若是沒有分組,對方接收的計算機根本就不知道從哪一位開始來作計算,也解析不了收到的數據。我發了16位你就按照16位來作計算嗎?我發100位你就按照100位作計算嗎?沒什麼意義是吧。所以要想讓底層的電信號有意義,必需要把底層的電信號作分組。我作好8位一組,那麼我收到數據,我就知道這幾個8位作一組,這幾個8位作一組。那麼每一個8位就能夠獲得一個肯定的數。分組是誰幹的活呢?物理層幹不了,這個是數據鏈路層乾的。

2、數據鏈路層

數據鏈路層由來:單純的電信號0和1沒有任何意義,必須規定電信號多少位一組,每組什麼意思

數據鏈路層的功能:定義了電信號的分組方式

2.1 以太網協議

早期的時候,數據鏈路層就是來對電信號來作分組的。之前每一個公司都有本身的分組方式,後來造成了統一的標準,即以太網協議ethernet

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

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

這就像寫信,發送者的地址(源地址)就是你家的地址,接收者地址(目標地址)就是對方的收信地址,你家的路由器就至關於郵局。其實在計算機通訊中的源地址和目標地址指的是Mac地址。

2.2 Mac地址

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

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

151-大白話OSI七層協議-mac網卡1.png?x-oss-process=style/watermark

151-大白話OSI七層協議-mac地址.jpg?x-oss-process=style/watermark

2.3 廣播地址

有了Mac地址之後,計算機就能夠通訊了,假設一個教室就是一個局域網(隔離的網絡),這個教室裏面有幾臺計算機,計算機的通訊和人的通訊是一個道理,把教室裏面的人都比做一個個計算機,假設教室裏面的人都是瞎子,其實計算機就是瞎子的,計算機通訊基本靠吼,如今我要找教室裏面的飛哥要戰狼2的片,而後我就吼一聲,說我要找飛哥要戰狼2的片,戰狼2的片就屬於個人數據,可是我在發的時候我是否是要標識我是誰,我要找誰,我是誰就是個人Mac地址,我要找誰就是飛哥的Mac地址,這兩個地址作數據包的頭部,再加上數據戰狼2的片就構成了一個數據幀。

這個數據包封裝好之後就往外發,到物理層之後就所有轉成二進制,往外發是怎麼發的呢?就是靠吼。即「我是nick,我找飛哥要戰狼2的片」。這麼吼了一嗓子之後,全屋子的人都能聽到,這就是廣播。

計算機底層,只要在一個教室裏(一個局域網),都是靠廣播的方式,吼。

151-大白話OSI七層協議-廣播.jpg?x-oss-process=style/watermark

廣播出去之後,全部人都聽得見,全部人都會拆開這個包,讀發送者是誰,接收者是誰,只要接收者不是本身就丟棄掉。對計算機來講,它會看本身的Mac地址,飛哥收到之後,他就會把片發給我,發送回來一樣採用廣播的方式了,靠吼。

同一個教室(同一個局域網)的計算機靠吼來通訊,那不一樣教室的計算機又如何?

好比說局域網1的pc1與局域網2的pc10如何通訊?你在教室1(局域網1)吼,教室2(局域網2)的人確定是聽不見的。這就是跨網絡進行通訊,數據鏈路層就解決不了這個問題了,這就得靠網絡層出面了。

注意:在講網絡層以前,其實基於廣播的這種通訊就能夠實現全世界通訊了,你吼一聲,若是全世界是一個局域網,全世界的計算機確定能夠聽得見,從理論上彷佛行得通,若是全世界的計算機都在吼,你想想,這是否是一個災難。所以,全世界不能是一個局域網。因而就有了網絡層。

3、網絡層

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

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

  • 對於上述的問題這就不只僅是效率低的問題了,這會是一種災難

151-大白話OSI七層協議-網絡層.jpg?x-oss-process=style/watermark

爲了解決上述災難,網絡層定義了一個IP協議,

你想,我是這個教室的一個學生,我想找隔壁教室一個叫老王的學生,我也不認識老王,那怎麼辦,我吼?老王在另一個教室確定是聽不到的。找教室的負責人,這個教室的負責人就負責和隔壁教室的負責人說話,說咱們教室的有個學生要找大家教室的老王。往外傳的東西交給負責人就能夠了,內部的話上面已經提到,經過廣播的方式,對外的東西廣播失效。教室的負責人就是網關,網關即網絡關口的意思。

Mac地址是用來標識你這個教室的某個位置,IP地址是用來標識你在哪一個教室(哪一個局域網)。你要跨網絡發包你是否是要知道對方的IP地址,好比你要訪問百度,你確定得知道百度服務器的IP地址。計算機在發包前,會判斷你在哪一個教室,對方在哪一個教室,若是在一個教室,基於Mac地址的廣播發包就OK了;若是不在一個教室,即跨網絡發包,那麼就會把你的包交給教室負責人(網關)來轉發。Mac地址及IP地址惟一標識了你在互聯網中的位置。

數據鏈路層中會把網絡層的數據包封裝到數數據鏈路層的數據位置,而後再添加上本身的包頭,再發給物理層,物理層發給網關,網關再發給對方教室的網關,對方教室的網關收到後在那個教室作廣播。

在數據鏈路層看,數據封裝了兩層,跟玩俄羅斯套娃有點相似,一層套了一層。

151-大白話OSI七層協議-網絡層包.jpg?x-oss-process=style/watermark

最終變成

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

如今來看另外一個問題,在吼以前怎麼知道對方的Mac地址?這就得靠ARP協議。

ARP協議的由來:在你找飛哥要片以前,你的先幹一件事,想辦法知道飛哥的Mac地址。即你的機器必須先發一個ARP包出去,ARP也是靠廣播的方式發,ARP發送廣播包的方式以下:

- 源Mac 目標Mac 源IP 目標IP 數據部分
發送端主機 發送端Mac FF:FF:FF:FF:FF:FF 172.16.10.10/24 172.16.10.11/24 數據

局域網中怎麼獲取對方的Mac地址:

確定要知道對方的IP地址,這是最基本的,就像你要訪問百度,確定得知道百度的域名,域名就是百度的IP地址。本身的IP能夠輕鬆得到,本身的Mac也輕鬆獲取,目標Mac爲12個F,咱們叫廣播地址,表達的意思是我想要獲取這個目標IP地址172.16.10.11的機器的Mac地址。Mac爲12個F表明的是一種功能,這個功能就是獲取對方的Mac地址,計算機的Mac永遠不多是12個F。假設是在本教室廣播,一嗓子吼出去了,全部人開始解包,只有IP地址是172.16.10.11的這我的纔會返回他的Mac地址,其餘人所有丟棄。發回來源Mac改爲飛哥本身的Mac地址,同時把飛哥的Mac地址放在數據部分。

跨網絡怎麼獲取對方的Mac地址:

經過IP地址區分,計算機運算判斷出飛哥不在同一個教室,目標IP就變成了網關的IP了。網關的IP在計算機上配死了,能夠輕鬆獲取。

- 源Mac 目標Mac 源IP 目標IP 數據部分
發送端主機 發送端Mac FF:FF:FF:FF:FF:FF 172.16.10.10/24 172.16.10.11/24 數據
- 源Mac 目標Mac 源IP 目標IP 數據部分
發送端主機 發送端Mac FF:FF:FF:FF:FF:FF 172.16.10.10/24 網關地址 數據
- 源Mac 目標Mac 源IP 目標IP 數據部分
發送端主機 發送端Mac 網關Mac 172.16.10.10/24 飛哥的IP 數據

注意:網關幫你去找飛哥,但對用戶來講,因爲速度太快咱們根本就感受不到網關的存在。

3.1 IP協議詳解

規定網絡地址的協議叫IP協議,它定義的地址稱之爲IP地址,普遍採用的v4版本即IPv4,它規定網絡地址由32位2進製表示
範圍0.0.0.0-255.255.255.255

  • 一個IP地址一般寫成四段十進制數,例:172.16.10.1

3.1.1 IP地址的兩部分

  1. 網絡部分:標識子網
  2. 主機部分:標識主機
  • 注意:單純的IP地址段只是標識了IP地址的種類,從網絡部分或主機部分都沒法辨識一個IP所處的子網

例:172.16.10.1與172.16.10.2並不能肯定兩者處於同一子網

3.2 子網掩碼詳解

所謂」子網掩碼」,就是表示子網絡特徵的一個參數。它在形式上等同於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
    • 255.255.255.0:11111111.11111111.11111111.00000000
    • AND運算得網絡地址結果:10101100.00010000.00001010.000000000->172.16.10.0
  • 172.16.10.2:10101100.00010000.00001010.000000010
    • 255.255.255.0:11111111.11111111.11111111.00000000
    • AND運算得網絡地址結果:10101100.00010000.00001010.000000000->172.16.10.0
  • 結果都是172.16.10.0,所以它們在同一個子網絡。

總結一下,IP協議的做用主要有兩個,一個是爲每一臺計算機分配IP地址,另外一個是肯定哪些地址在同一個子網絡。

3.3 IP數據包詳解

IP數據包也分爲head和data部分,無須爲IP包定義單獨的欄位,直接放入以太網包的data部分

  • head:長度爲20到60字節
  • data:最長爲65,515字節

注意:以太網數據包的"數據"部分,最長只有1500字節。所以,若是IP數據包超過了1500字節,它就須要分割成幾個以太網數據包,分開發送了。

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

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

3.4 ARP協議詳解

arp協議由來:計算機通訊基本靠吼,即廣播的方式,全部上層的包到最後都要封裝上以太網頭,而後經過以太網協議發送,在談及以太網協議時候,我門瞭解到:通訊是基於Mac的廣播方式實現,計算機在發包時,獲取自身的Mac是容易的,如何獲取目標主機的Mac,就須要經過arp協議

arp協議功能:廣播的方式發送數據包,獲取目標主機的Mac地址

協議工做方式:每臺主機IP都是已知的,例如:主機172.16.10.10/24訪問172.16.10.11/24

1.首先經過IP地址和子網掩碼區分出本身所處的子網

場景 數據包地址
同一子網 目標主機Mac,目標主機IP
不一樣子網 網關Mac,目標主機IP

2.分析172.16.10.10/24與172.16.10.11/24處於同一網絡(若是不是同一網絡,那麼下表中目標IP爲172.16.10.1,經過arp獲取的是網關的Mac)

- 源Mac 目標Mac 源IP 目標IP 數據部分
發送端主機 發送端Mac FF:FF:FF:FF:FF:FF 172.16.10.10/24 172.16.10.11/24 數據

3.這個包會以廣播的方式在發送端所處的自網內傳輸,全部主機接收後拆開包,發現目標IP爲本身的,就響應,返回本身的Mac

4、傳輸層

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

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

傳輸層功能:創建端口到端口的通訊

補充:端口範圍0-65535,0-1023爲系統佔用端口

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

4.1 TCP協議

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

4.2 UDP協議

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

4.3 TCP報文

151-大白話OSI七層協議-tcp報文.jpg?x-oss-process=style/watermark

4.4 TCP三次握手和四次揮手

151-大白話OSI七層協議-tcp三次握手和四次揮手.jpg?x-oss-process=style/watermark

5、應用層

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

應用層功能:規定應用程序的數據格式。

  • 例:TCP協議能夠爲各類各樣的程序傳遞數據,好比Email、WWW、FTP等等。那麼,必須有不一樣協議規定電子郵件、網頁、FTP數據的格式,這些應用程序協議就構成了」應用層」。

151-大白話OSI七層協議-應用層.jpg?x-oss-process=style/watermark

注意:數據通過以上幾層的折騰,已經不成樣子了。

151-大白話OSI七層協議-七層數據內容.jpg?x-oss-process=style/watermark

1、背景描述

經過OSI七層網絡模型中IP層的介紹,咱們知道網絡層,能夠實現兩個主機之間的通訊。可是這並不具體,由於,真正進行通訊的實體是在主機中的進程,是一個主機中的一個進程與另一個主機中的一個進程在交換數據。IP協議雖然能把數據報文送到目的主機,可是並無交付給主機的具體應用進程。而端到端的通訊才應該是應用進程之間的通訊。

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

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

2、經常使用的熟知端口號

應用程序 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

3、TCP概述

TCP把鏈接做爲最基本的對象,每一條TCP鏈接都有兩個端點,這種端點咱們叫做套接字(socket),它的定義爲端口號拼接到IP地址即構成了套接字,例如,若IP地址爲192.3.4.16 而端口號爲80,那麼獲得的套接字爲192.3.4.16:80。

4、TCP報文首部

  1. 源端口和目的端口,各佔2個字節,分別寫入源端口和目的端口;
  2. 序號,佔4個字節,TCP鏈接中傳送的字節流中的每一個字節都按順序編號。例如,一段報文的序號字段值是 301 ,而攜帶的數據共有100字段,顯然下一個報文段(若是還有的話)的數據序號應該從401開始;
  3. 確認號,佔4個字節,是指望收到對方下一個報文的第一個數據字節的序號。例如,B收到了A發送過來的報文,其序列號字段是501,而數據長度是200字節,這代表B正確的收到了A發送的到序號700爲止的數據。所以,B指望收到A的下一個數據序號是701,因而B在發送給A的確認報文段中把確認號置爲701;
  4. 數據偏移,佔4位,它指出TCP報文的數據距離TCP報文段的起始處有多遠;
  5. 保留,佔6位,保留從此使用,但目前應都位0;
  6. 緊急URG,當URG=1,代表緊急指針字段有效。告訴系統此報文段中有緊急數據;
  7. 確認ACK,僅當ACK=1時,確認號字段纔有效。TCP規定,在鏈接創建後全部報文的傳輸都必須把ACK置1;
  8. 推送PSH,當兩個應用進程進行交互式通訊時,有時在一端的應用進程但願在鍵入一個命令後當即就能收到對方的響應,這時候就將PSH=1;
  9. 復位RST,當RST=1,代表TCP鏈接中出現嚴重差錯,必須釋放鏈接,而後再從新創建鏈接;
  10. 同步SYN,在鏈接創建時用來同步序號。當SYN=1,ACK=0,代表是鏈接請求報文,若贊成鏈接,則響應報文中應該使SYN=1,ACK=1;
  11. 終止FIN,用來釋放鏈接。當FIN=1,代表此報文的發送方的數據已經發送完畢,而且要求釋放;
  12. 窗口,佔2字節,指的是通知接收方,發送本報文你須要有多大的空間來接受;
  13. 檢驗和,佔2字節,校驗首部和數據這兩部分;
  14. 緊急指針,佔2字節,指出本報文段中的緊急數據的字節數;
  15. 選項,長度可變,定義一些其餘的可選的參數。

5、TCP鏈接的創建(三次握手)

120-TCP三次握手和四次揮手-三次握手.gif

  • 最開始的時候客戶端和服務器都是處於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狀態,此後雙方就能夠開始通訊了。

120-TCP三次握手和四次揮手-三次握手靜態.jpg?x-oss-process=style/watermark

6、TCP四次揮手

120-TCP三次握手和四次揮手-四次揮手.gif

  • 數據傳輸完畢後,雙方均可釋放鏈接。最開始的時候,客戶端和服務器都是處於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鏈接的時間要比客戶端早一些。

120-TCP三次握手和四次揮手-四次揮手靜態.png?x-oss-process=style/watermark

7、面試題

7.1 爲何客戶端最後還要等待2MSL?

MSL(Maximum Segment Lifetime),TCP容許不一樣的實現能夠設置不一樣的MSL值。

  1. 保證客戶端發送的最後一個ACK報文可以到達服務器,由於這個ACK報文可能丟失,站在服務器的角度看來,我已經發送了FIN+ACK報文請求斷開了,客戶端尚未給我回應,應該是我發送的請求斷開報文它沒有收到,因而服務器又會從新發送一次,而客戶端就能在這個2MSL時間段內收到這個重傳的報文,接着給出迴應報文,而且會重啓2MSL計時器。
  2. 防止相似與「三次握手」中提到了的「已經失效的鏈接請求報文段」出如今本鏈接中。客戶端發送完最後一個確認報文後,在這個2MSL時間中,就可使本鏈接持續的時間內所產生的全部報文段都從網絡中消失。這樣新的鏈接中不會出現舊鏈接的請求報文。

7.2 爲何創建鏈接是三次握手,關閉鏈接確是四次揮手呢?

創建鏈接的時候,服務器在LISTEN狀態下,收到創建鏈接請求的SYN報文後,把ACK和SYN放在一個報文裏發送給客戶端。而關閉鏈接時,服務器收到對方的FIN報文時,僅僅表示對方再也不發送數據了可是還能接收數據,而本身也未必所有數據都發送給對方了,因此己方能夠當即關閉,也能夠發送一些數據給對方後,再發送FIN報文給對方來表示贊成如今關閉鏈接,所以,己方ACK和FIN通常都會分開發送,從而致使多了一次。

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

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

1、什麼是Scoket

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

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

121-基於TCP協議的套接字編程-socket層.jpg?x-oss-process=style/watermark

  • 注意:也有人將socket說成ip+port,ip是用來標識互聯網中的一臺主機的位置,而port是用來標識這臺機器上的一個應用程序,ip地址是配置到網卡上的,而port是應用程序開啓的,ip與port的綁定就標識了互聯網中獨一無二的一個應用程序,而程序的pid是同一臺機器上不一樣進程或者線程的標識。

2、套接字發展史及分類

套接字起源於 20 世紀 70 年代加利福尼亞大學伯克利分校版本的 Unix,即人們所說的 BSD Unix。 所以,有時人們也把套接字稱爲「伯克利套接字」或「BSD 套接字」。一開始,套接字被設計用在同 一臺主機上多個應用程序之間的通信。這也被稱進程間通信,或 IPC。套接字有兩種(或者稱爲有兩個種族),分別是基於文件型的和基於網絡型的。

2.1 基於文件類型的套接字家族

套接字家族的名字:AF_UNIX

unix一切皆文件,基於文件的套接字調用的就是底層的文件系統來取數據,兩個套接字進程運行在同一機器,能夠經過訪問同一個文件系統間接完成通訊

2.2 基於網絡類型的套接字家族

套接字家族的名字:AF_INET

(還有AF_INET6被用於ipv6,還有一些其餘的地址家族,不過,他們要麼是隻用於某個平臺,要麼就是已經被廢棄,或者是不多被使用,或者是根本沒有實現,全部地址家族中,AF_INET是使用最普遍的一個,python支持不少種地址家族,可是因爲咱們只關心網絡編程,因此大部分時候我麼只使用AF_INET)

3、套接字工做流程

一個生活中的場景。你要打電話給一個朋友,先撥號,朋友聽到電話鈴聲後提起電話,這時你和你的朋友就創建起了鏈接,就能夠講話了。等交流結束,掛斷電話結束這次交談。 生活中的場景就解釋了這工做原理。

121-基於TCP協議的套接字編程-socket流程.jpg?x-oss-process=style/watermark

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

import socket

# socket_family 能夠是 AF_UNIX 或 AF_INET。socket_type 能夠是 SOCK_STREAM 或 SOCK_DGRAM。protocol 通常不填,默認值爲 0
socket.socket(socket_family, socket_type, protocal=0)

# 獲取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 獲取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 因爲 socket 模塊中有太多的屬性。咱們在這裏破例使用了'from module import *'語句。使用 'from socket import *',咱們就把 socket 模塊裏的全部屬性都帶到咱們的命名空間裏了,這樣能大幅減短咱們的代碼
tcpSock = socket(AF_INET, SOCK_STREAM)

121-基於TCP協議的套接字編程-小兵潮.gif

3.1 服務端套接字函數

方法 用途
s.bind() 綁定(主機,端口號)到套接字
s.listen() 開始TCP監聽
s.accept() 被動接受TCP客戶的鏈接,(阻塞式)等待鏈接的到來

3.2 客戶端套接字函數

方法 用途
s.connect() 主動初始化TCP服務器鏈接
s.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常

3.3 公共用途的套接字函數

方法 用途
s.recv() 接收TCP數據
s.send() 發送TCP數據(send在待發送數據量大於己端緩存區剩餘空間時,數據丟失,不會發完)
s.sendall() 發送完整的TCP數據(本質就是循環調用send,sendall在待發送數據量大於己端緩存區剩餘空間時,數據不丟失,循環調用send直到發完)
s.recvfrom() 接收UDP數據
s.sendto() 發送UDP數據
s.getpeername() 鏈接到當前套接字的遠端的地址
s.getsockname() 當前套接字的地址
s.getsockopt() 返回指定套接字的參數
s.setsockopt() 設置指定套接字的參數
s.close() 關閉套接字

3.4 面向鎖的套接字方法

方法 用途
s.setblocking() 設置套接字的阻塞與非阻塞模式
s.settimeout() 設置阻塞套接字操做的超時時間
s.gettimeout() 獲得阻塞套接字操做的超時時間

3.5 面向文件的套接字的函數

方法 用途
s.fileno() 套接字的文件描述符
s.makefile() 建立一個與該套接字相關的文件

121-基於TCP協議的套接字編程-打電話.jpg?x-oss-process=style/watermark

4、基於TCP協議的套接字編程(簡單)

  • 能夠經過netstat -an | findstr 8080查看套接字狀態

4.1 服務端

import socket

#一、買手機
phone = socket.socket(socket.AF_INET,
                      socket.SOCK_STREAM)  #tcp稱爲流式協議,udp稱爲數據報協議SOCK_DGRAM
# print(phone)

#二、插入/綁定手機卡
# 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())

# import time
# time.sleep(500)
#六、掛掉電話鏈接
conn.close()

#七、關機
phone.close()

4.2 客戶端

import socket
# socket.AF
#一、買手機
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)

# import time
# time.sleep(500)
#四、關閉
phone.close()

5、基於TCP協議的套接字編程(循環)

5.1 服務端

import socket

#一、買手機
phone = socket.socket(socket.AF_INET,
                      socket.SOCK_STREAM)  #tcp稱爲流式協議,udp稱爲數據報協議SOCK_DGRAM
# print(phone)

#二、插入/綁定手機卡
# 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()

5.2 客戶端1

import socket

#一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# print(phone)
#二、撥電話
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()

5.3 客戶端2

import socket

#一、買手機
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# print(phone)
#二、撥電話
phone.connect(('127.0.0.1', 8080))  # 指定服務端ip和端口

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

#四、關閉
phone.close()

6、地址佔用問題

有的同窗在重啓服務端時可能會遇到:

121-基於TCP協議的套接字編程-bug.png?x-oss-process=style/watermark

這個是因爲你的服務端仍然存在四次揮手的time_wait狀態在佔用地址(若是不懂,請深刻研究1.tcp三次握手,四次揮手 2.syn洪水攻擊 3.服務器高併發狀況下會有大量的time_wait狀態的優化方法)

6.1 方法一

# 加入一條socket配置,重用ip和端口

phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8080))

6.2 方法二(Linux)

發現系統存在大量TIME_WAIT狀態的鏈接,經過調整linux內核參數解決,
vi /etc/sysctl.conf

編輯文件,加入如下內容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
 
而後執行 /sbin/sysctl -p 讓參數生效。
 
net.ipv4.tcp_syncookies = 1 表示開啓SYN Cookies。當出現SYN等待隊列溢出時,啓用cookies來處理,可防範少許SYN攻擊,默認爲0,表示關閉;

net.ipv4.tcp_tw_reuse = 1 表示開啓重用。容許將TIME-WAIT sockets從新用於新的TCP鏈接,默認爲0,表示關閉;

net.ipv4.tcp_tw_recycle = 1 表示開啓TCP鏈接中TIME-WAIT sockets的快速回收,默認爲0,表示關閉。

net.ipv4.tcp_fin_timeout 修改系統默認的 TIMEOUT 時間
相關文章
相關標籤/搜索