面試準備5

今天來記錄一下網絡編程:對於網絡的理解以及各種通信協議,這個也是後端開發的基礎知識
(1)網絡通信的概念
什麼是網絡:網絡就是一種輔助雙方或者多方能夠連接在一起的工具,就是爲了聯通多方之後進行通信用的,把數據從一方傳遞給另外一方,爲了讓在不同的電腦上運行的軟件之間能夠互相傳遞數據,就需要藉助網絡的功能。
簡練:使用網絡能夠把多方鏈接在一起,然後可以進行數據傳遞,所謂的網絡編程就是讓在不同的電腦上的軟件能夠進行數據傳遞,即進程之間的通信

(2)通信協議:tcp/ip
白話協議:爲了解決不同種族人之間的語言溝通障礙,現規定國際通用語言是英語,這就是一個規定,這就是協議。就像說不同語言的人溝通一樣,只要有一種大家都認可都遵守的協議即可,那麼這個計算機都遵守的網絡通信協議叫做 TCP/IP協議
—TCP/IP協議不是兩種協議,他是一種協議族

(3)TCP/IP協議中的端口:端口針對於有網絡需求的進程來說的
什麼是端口:端口就好比一個房子的門,是出入這間房子的必經之路。***如果一個進程需要收發網絡數據,那麼就需要有這樣的端口***在linux系統中,端口可以有65536(2的16次方)個之多,既然有這麼多,操作系統爲了統一管理,所以進行了編號,這就是端口號(形象的比喻:端口就是一個門,進程是房子)想要進房子首先需要通過門—端口

端口號:端口是通過端口號來標記的,端口號只有整數,範圍是從0到65535,端口號不是隨意使用的,而是按照一定的規定進行分配的,有知名端口以及動態端口

動態端口:動態端口的範圍是從1024到65535,之所以稱爲動態端口,是因爲它一般不固定分配某種服務,而是動態分配。
動態分配是指當一個系統進程或應用程序進程需要網絡通信時,它向主機申請一個端口,主機從可用的端口號中分配一個供它使用。當這個進程關閉時,同時也就釋放了所佔用的端口號。

查看端口: netstat -an 查看端口狀態
或者: lsof -i:端口號 推薦使用:lsof -i:端口號
或者:netstat -ap | grep 端口號

總結:一臺擁有IP地址的主機可以提供許多服務,比如HTTP(萬維網服務)、FTP(文件傳輸)、SMTP(電子郵件)等,這些服務完全可以通過1個IP地址來實現。那麼,主機是怎樣區分不同的網絡服務呢?顯然不能只靠IP地址,因爲IP地址與網絡服務的關係是一對多的關係。實際上是通過“IP地址+端口號”來區分不同的服務的。需要注意的是,端口並不是一一對應的。比如你的電腦作爲客戶機訪問一臺WWW服務器時,WWW服務器使用“80”端口與你的電腦通信,但你的電腦則可能使用“3457”這樣的端口。(ip地址和端口)

(4)ip地址
ip地址:用來在網絡中標記一臺電腦的一串數字,比如192.168.1.1;在本地局域網上是惟一的。每一個IP地址包括兩部分:網絡地址和主機地址。ip地址分爲A、B、C、D、E類

私有IP:在這麼多網絡IP中,國際規定有一部分IP地址是用於我們的局域網使用,也就是屬於私網IP,不在公網中使用,他們的範圍是:
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255

IP地址127.0.0.1~127.255.255.255用於迴路測試,如:127.0.0.1可以代表本機IP地址,用 http://127.0.0.1 就可以測試本機
中配置的Web服務器。

(5)子網掩碼
子網掩碼的功能就是確定IP地址中哪些是網絡號、哪些是主機號

(6)通信基元–socket
本地的進程間通信:
隊列
同步(互斥鎖、條件變量)
這種通信都是在一臺機器上不同進程之間的通信方式,網絡中進程之間如何通信?
----需要解決的問題是如何唯一標識一個進程,否則通信無從談起,在本地可以通過進程PID來唯一標識一個進程,但是在網絡中這是行不通的。TCP/IP協議已經幫我們解決類這個問題,網絡層的ip地址可以唯一標識網絡中的主機,而傳輸層的“協議+端口”可以唯一標識主機中的引用程序(進程)。這樣利用ip地址、協議、端口就可以標識網絡的進程類,網絡中的進程通信就可以利用這個標誌與其他進程進行交互

什麼是scoket: socket(套接字)是進程間通信的一種方式,它與其他進程間的一個主要不同是,他能實現不同主機間的進程間通信,網絡上各種各樣的服務大多都是基於Socket來完成通信的,我們每天瀏覽網頁、QQ、wechat等等

(7)創建socket
在python中使用socket模塊中的socket就可以創建socket

創建一個tcp	socket(tcp套接字)
import	socket
s	=	socket.socket(socket.AF_INET,	socket.SOCK_STREAM)
print	'Socket	Created'
創建一個udp	socket(udp套接字)
import	socket
s	=	socket.socket(socket.AF_INET,	socket.SOCK_DGRAM)
print	'Socket	Created'

(8)UDP介紹
UDP和TCP一樣都是網絡通信協議–用於解決網絡中數據的傳輸問題
UDP—用戶數據報協議,是一個無連接(對於無連接的理解,客戶端和服務器端在通信之前不需要進行連接,然而TCP需要)的簡單的面向數據報的運輸層協議

UDP性能:UDP不提供可靠性,它只是把應用程序傳給IP層的數據報發送出去,但是並不能保證它們能到達目的地。由於UDP在傳輸數據報前不用在客戶和服務器之間建立一個連接,且沒有超時重發等機制,故而傳輸速度很快。UDP是一種面向無連接的協議,每個數據報都是一個獨立的信息,包括完整的源地址或目的地址,它在網絡上以任何可能的路徑傳往目的地,因此能否到達目的地,到達目的地的時間以及內容的正確性都是不能被保證的。

UDP特點:
UDP是面向無連接的通訊協議,UDP數據包括目的端口號和源端口號信息,由於通訊不需要連接,所以可以實現廣播發送。 UDP傳輸數據時有大小限制,每個被傳輸的數據報必須限定在64KB之內。UDP是一個不可靠的協議,發送方所發送的數據報並不一定以相同的次序到達接收方。

UDP適用情況:
UDP是面向消息的協議,通信時不需要建立連接,數據的傳輸自然是不可靠的,UDP一般用於多點通信和實時的數據業務,比如
語音廣播
視頻
QQ
TFTP(簡單文件傳送)
SNMP(簡單網絡管理協議)
RIP(路由信息協議,如報告股票市場,航空信息)
DNS(域名解釋)
UDP操作簡單,而且僅需要較少的監護,因此通常用於局域網高可靠性的分散系統中client/server應用程序。例如視頻會議系統,並不要求音頻視頻數據絕對的正確,只要保證連貫性就可以了,這種情況下顯然使用UDP會更合理一些。
UDP只管傳送,不管對方有沒有接收到信息-------(這個就是數據傳輸不可靠的因素)。

(9)udp網絡程序-發送數據
UDP通信的過程圖:
在這裏插入圖片描述
創建一個udp客戶端程序的流程是簡單,具體步驟如下:

  1. 創建客戶端套接字
  2. 發送/接收數據
  3. 關閉套接字

客戶端:

#coding=utf-8
from	socket	import	*
#1.	創建套接字
udpSocket	=	socket(AF_INET,	SOCK_DGRAM)
#2.	準備接收方的地址
sendAddr	=	('192.168.1.103',	8080)
#3.	從鍵盤獲取數據
sendData	=	raw_input("請輸入要發送的數據:")
#4.	發送數據到指定的電腦上
udpSocket.sendto(sendData,	sendAddr)
#5.	關閉套接字
udpSocket.close()

----創建udp網絡程序-接收數據
一個udp網絡程序,可以不綁定,此時操作系統會隨機進行分配一個端口,如果重新運行次程序端口可能會發生變化一個udp網絡程序,也可以綁定信息(ip地址,端口號),如果綁定成功,那麼操作系統用這個端口號來進行區別收到的網絡數據是否是此進程的

udp總結:

  1. udp是TCP/IP協議族中的一種協議能夠完成不同機器上的程序間的數據通信
  2. udp服務器、客戶端
    udp的服務器和客戶端的區分:往往是通過請求服務和提供服務 來進行區分:
    請求服務的一方稱爲:客戶端
    提供服務的一方稱爲:服務器
    3.udp綁定問題
    一般情況下,服務器端,需要綁定端口,目的是爲了讓其他的客戶端能夠正確發送到此進程.客戶端,一般不需要綁定,而是讓操作系統隨機分配,這樣就不會因爲需要綁定的端口被佔用而導致程序無法運行的情況

(10)TFTP協議介紹
TFTP(Trivial File Transfer Protocol,簡單文件傳輸協議)是TCP/IP協議族中的一個用來在客戶端與服務器之間進行簡單文件傳輸的協議

(11)tcp相關介紹
udp通信模型:udp通信模型中,在通信開始之前,不需要建立相關的連接,只需要發送數據就可以,類似於生活中的“寫信”
UDP通信模型圖:
在這裏插入圖片描述
tcp通信模型
TCP通信模型中,在通信開始之前,一定要先建立相關的鏈接,才能發送數據,類似於生活中,“打電話”"
UDP/TCP都是網絡通信協議-------
UDP:無連接,用戶數據報協議
TCP:有連接
TCP網絡通信協議圖:
在這裏插入圖片描述tcp服務器:比作生活中的電話機
如果想讓別人能更夠打通咱們的電話獲取相應服務的話,需要做一下幾件情:

  1. 買個手機
  2. 插上手機卡
  3. 設計手機爲正常接聽狀態(即能夠響鈴)
  4. 靜靜的等着別人撥打
    tcp服務器
    如同上面的電話機過程一樣,在程序中,如果想要完成一個tcp服務器的功
    能,需要的流程如下:
  5. socket創建一個套接字
  6. bind綁定ip和port
  7. listen使套接字變爲可以被動鏈接
  8. accept等待客戶端的鏈接
  9. recv/send接收發送數據
    一個簡單的tcp服務器代碼:

```bash
#coding=utf-8
from	socket	import	*
#	創建socket
tcpSerSocket	=	socket(AF_INET,	SOCK_STREAM)
#	綁定本地信息
address	=	('',	7788)
tcpSerSocket.bind(address)
#	使用socket創建的套接字默認的屬性是主動的,使用listen將其變爲被動的,這樣就可以接收
tcpSerSocket.listen(5)
#	如果有新的客戶端來鏈接服務器,那麼就產生一個新的套接字專⻔爲這個客戶端服務器
#	newSocket用來爲這個客戶端服務
#	tcpSerSocket就可以省下來專⻔等待其他新客戶端的鏈接
newSocket,	clientAddr	=	tcpSerSocket.accept()
#	接收對方發送過來的數據,最大接收1024個字節
recvData	=	newSocket.recv(1024)
print	'接收到的數據爲:',recvData
#	發送一些數據到客戶端
newSocket.send("thank	you	!")
#	關閉爲這個客戶端服務的套接字,只要關閉了,就意味着爲不能再爲這個客戶端服務了,如果還需
newSocket.close()
#	關閉監聽套接字,只要這個套接字關閉了,就意味着整個程序不能再接收任何新的客戶端的連接
tcpSerSocket.close()

tcp服務器的一套流程
-----tcp客戶端構建流程
tcp的客戶端要比服務器端簡單很多,如果說服務器端是需要自己買手機、查手機卡、設置鈴聲、等待別人打電話流程的話,那麼客戶端就只需要找一個電話亭,拿起電話撥打即可,流程要少很多
客戶端:使用服務器的ip+端口進行打電話
具體的代碼如下:

#coding=utf-8
from	socket	import	*
#	創建socket
tcpClientSocket	=socket(AF_INET,SOCK_STREAM)
#	鏈接服務器
serAddr	=('192.168.1.102',	7788)
tcpClientSocket.connect(serAddr)
#	提示用戶輸入數據
sendData=raw_input("請輸入要發送的數據:")
tcpClientSocket.send(sendData)
#	接收對方發送過來的數據,最大接收1024個字節
recvData=tcpClientSocket.recv(1024)
print'接收到的數據爲:',recvData
#	關閉套接字
tcpClientSocket.close()

客戶端的寫法比較簡單

(12)網絡通信過程
網絡通信組網,多臺電腦組網、集線器組網、交換機組網、路由器組網,交換機和路由器組網。

集線器組網:
集線器能夠完成多個電腦的連接,每個數據包的發送都是以廣播的形式進行的,容易堵塞網絡

網絡交換機組網:
網絡交換機是一個擴大網絡的器材,能爲子網絡中提供更多的連接端口,以便鏈接更多的計算機

路由器組網:
路由器稱爲網關設備,是用於連接多個邏輯上分開的網絡,邏輯網絡是代表一個單獨的網絡或者一個子網。當數據從一個子網輸到涼意個子網時,可通過路由功能來完成

(13)tcp的三次握手
當兩個socket建立連接時需要進行三次握手的操作(也就是客戶端和服務器端建立連接時)
客戶端 服務器端
第一次握手:客戶端發送請求,服務器端接受請求
第二次握手:服務器端接受到請求,反饋給客戶端
第三次握手:客戶端接受到服務器端的反饋,發送確認信息,建立連接完成握手操作

(14)tcp四次揮手
兩個socket之間要斷開連接,客戶端和服務器端需要斷開連接。
第一次揮手:客戶端給服務器端發送fn
第二次揮手:服務器收到fn,並反饋
第三次揮手:服務器再次發送信息給客戶端
第四次揮手:客戶端接受信息,給服務器端發送確認關閉連接,完成斷開連接的操作

(15)tcp的長連接和短連接
TCP在真正的讀寫操作之前,server與client之間必須建立一個連接,當讀寫操作完成後,雙方不再需要這個連接時可以釋放這個連接
連接的建立通過三次握手,釋放則需要四次揮手,所以說每個連接的建立都是需要資源消耗和時間消耗的。
短連接:
在這裏插入圖片描述
TCP短連接
模擬一種TCP短連接的情況:
client向server發起連接請求
server接到請求,雙方建立連接
client向server發送消息
server迴應client
一次讀寫完成,此時雙方任何一個都可以發起close操作

TCP長連接:
在這裏插入圖片描述
在這裏插入圖片描述
再模擬一種⻓連接的情況:
client向server發起連接
server接到請求,雙方建立連接
client向server發送消息
server迴應client
一次讀寫完成,連接不關閉
後續讀寫操作…
長時間操作之後client發起關閉請求

(16)TCP長/短連接的優點和缺點
TCP⻓/短連接的優點和缺點
⻓連接可以省去較多的TCP建立和關閉的操作,減少浪費,節約時間。
對於頻繁請求資源的客戶來說,較適用⻓連接。
client與server之間的連接如果一直不關閉的話,會存在一個問題,
隨着客戶端連接越來越多,server早晚有扛不住的時候,這時候server端需要採取一些策略,如關閉一些⻓時間沒有讀寫事件發生的連接,這樣可以避免一些惡意連接導致server端服務受損;
如果條件再允許就可以以客戶端機器爲顆粒度,限制每個客戶端的最大⻓連接數,這樣可以完全避免某個蛋疼的客戶端連累後端服務。短連接對於服務器來說管理較爲簡單,存在的連接都是有用的連接,不需要額外的控制手段。但如果客戶請求頻繁,將在TCP的建立和關閉操作上浪費時間和帶寬。

(17)TCP長/短連接的應用場景
長連接多用於操作頻繁,點對點的通訊,而且連接數不能太多的情況,
場景:
一般數據庫的連接需要用長連接,如果用短連接頻繁的通信會造成socket的錯誤

像WEB網站的http服務一般都用短連接,因爲長連接對於服務端來說會耗費一定的資源,如果用長連接,而且同時有成千上萬的用戶,如果每個用戶都佔用一個連接,可想而知,併發量太大,所以web端使用短連接比較好

(18)socket中listen的隊列長度
listen的隊列長度,寫在服務器端中,listen中的black表示已經建立連接和半連接達到設定值,那麼新客戶端就不會connect成功,而是等待服務器

在ubuntu中查看域名解析器的ip地址方法:nslookup 域名
nslookup www.baidu.com

(19)服務器
—1. 單進程服務器: (同一時刻只能爲同一個客戶端進行服務)完成一個簡單的TCP服務器,同一時刻只能爲一個客戶進行服務,不能同時爲多個客戶服務。當服務器爲一個客戶端服務時,而另外的客戶端發起了connect,只要服務器listen的隊列有空閒的位置,就會爲這個新客戶端進行連接,並且客戶端可以發送數據,但當服務器爲這個新客戶端服務時,可能一次性把所有數據接收完畢。
—2.多進程服務器(不推薦使用的)
通過爲每個客戶端創建一個進程的方式,能夠同時爲多個客戶端進行服務。
當客戶端不是特別多的時候,這種方式還行,如果有幾百上千個,就不可取了,因爲每次創建進程等過程需要好較大的資源。來一個客戶端服務器就會單獨開一個進程來對其進行服務

—3. 多線程服務器
通過爲每個客戶端創建一個線程的方式,能夠同時爲多個客戶端進行服務。

—4. 單進程服務器-非堵塞模式

—5. select版-TCP服務器
在多路複用的模型中,比較常用的有select模型和epoll模型。這兩個都是系統接口,由操作系統提供。
優點:select目前幾乎在所有的平臺上支持,其良好跨平臺支持也是它的一個優點。

缺點: select的一個缺點在於單個進程能夠監視的文件描述符的數量存在最大限制,在Linux上一般爲1024。當套接字比較多的時候,每次select()都要通過遍歷FD_SETSIZE個Socket來完成調度,不管哪個Socket是活躍的,都遍歷一遍。這會浪費很多CPU時間

—6. epoll版-TCP服務器
epoll的優點:
沒有最大併發連接的限制,能打開的FD(指的是文件描述符,通俗的理解就是套接字對應的數字編號)的上限遠大於1024

(20)協程
協程,又稱爲微線程,纖程–coroutine
通俗的理解:在一個線程中的某個函數,可以在任何地方保存當前函數的一些臨時變量等信息,然後切換到另外一個函數中執行,注意不是通過調用函數的方式做到的,並且切換的次數以及什麼時候再切換到原來的函數都由開發者自己確定。

核心:單線程中,由開發者來進行調度的(切換不同程序的執行)

協程和線程差異: 那麼這個過程看起來比線程差不多。其實不然, 線程切換從系統層面遠不止保存和恢復 CPU上下文這麼簡單。 操作系統爲了程序運行的高效性每個線程都有自己緩存Cache等等數據,操作系統還會幫你做這些數據的恢復操作。所以線程的切換非常耗性能。但是協程的切換隻是單純的操作CPU的上下文,所以一秒鐘切換個上百萬次系統都抗的住。
簡單版本協程的實現:

import	time
def	A():
	while	True:
		print("----A---")
		yield
		time.sleep(0.5)
def	B(c):
	while	True:
			print("----B---")
			c.next()
		    time.sleep(0.5)
if	__name__=='__main__':
			a	=	A()
			B(a)

(21)協程-greenlet版
爲了更好使用協程來完成多任務,python中的greenlet模塊對其封裝,從而使得切換任務變的更加簡單

(22)gevent
greenlet已經實現了協程,但是這個還的人工切換,是不是覺得太麻煩了,不要捉急,python還有一個比greenlet更強大的並且能夠自動切換任務的模塊 gevent 其原理是當一個greenlet遇到IO(指的是input output 輸入輸出,比如網絡、文件操作等)操作時,比如訪問網絡,就自動切換到其他的greenlet,等到IO操作完成,再在適當的時候切換回來繼續執行。由於IO操作非常耗時,經常使程序處於等待狀態,有了gevent爲我們自動切換協程,就保證總有greenlet在運行,而不是等待IO

(23)思考協程
tornado中封裝了協程異步,使用協程的方式來實現異步的操作
----異步web操作,服務器作爲客戶端的時候,需要進行異步的操作,保證作爲服務器的功能(tornado中是單線程,單進程的,實現高併發的是epoll機制,以及協程操作)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章