知識儲備html


1 # C/S架構 2 client<---->server 3 # B/S架構 4 browser<---->server
物理層功能:主要是基於電器特性發送高低電壓(電信號),高電壓對應數字1,低電壓對應數字0shell
數據鏈路層由來:單純的電信號0和1沒有任何意義,必須規定電信號多少位一組,每組什麼意思json
數據鏈路層功能:定義了電信號的分組方式windows
以太網協議:緩存
造成統一標準,以太網協議ethernet安全
ethernet規定服務器
- 一組電信號構成一個數據包,叫作’幀‘
- 每一數據幀分紅:包頭head和數據data兩部分
head包含:(固定18個字節)
- 源,6個字節
- 目,6個字節
- 數據類型,6個字節
data包含:(最短46字節,最長1500字節)
- 數據包的具體內容


head長度+data長度=最短64字節,最長1518字節,超過最大限制就分片發送
網絡層由來:有了mac地址,同一網絡內的兩臺主機就能夠通訊了(一臺主機經過arp協議獲取另一臺主機的mac地址),ethernet採用最原始的方式,廣播的方式進行通訊,即計算機通訊基本靠吼。
如今還須要一種手段來斷定,必須找出一種方法來區分哪些計算機屬於同一廣播域,哪些不是,若是是就採用廣播的方式發送,若是不是,就採用路由的方式(向不一樣廣播域/子網分發數據包)。
網絡層功能:引入一套新的地址用來區分不一樣的廣播域/子網,這套地址即網絡地址
傳輸層的由來:傳輸層如下都是由操做系統控制,網絡層的ip幫咱們區分子網,以太網層的mac幫咱們找到主機,而後你們使用的都是應用程序,你的電腦上可能同時開啓qq,暴風影音,等多個應用程序,
那麼咱們經過ip和mac找到了一臺特定的主機,如何標識這臺主機上的應用程序,答案就是端口,端口即應用程序與網卡關聯的編號。
傳輸層功能:創建端口到端口的通訊
補充:端口範圍0-65535,0-1023爲系統佔用端口
tcp協議:
可靠傳輸,TCP數據包沒有長度限制,理論上能夠無限長,可是爲了保證網絡的效率,一般TCP數據包的長度不會超過IP數據包的長度,以確保單個TCP數據包沒必要再分割。
以太網頭 | ip 頭 | tcp頭 | 數據 |
udp協議:
不可靠傳輸,」報頭」部分一共只有8個字節,總長度不超過65,535字節,正好放進一個IP數據包。
以太網頭 | ip頭 | udp頭 | 數據 |
tcp報文
tcp三次握手和四次揮手
tcp創建的是雙向連接


C -----------------------》 S C <----------------------- S


C ---- syn=1 seq=x ----> S S ---- ack=1+x syn=1 seq=y ----> C C ---- ack=1+y ----> S


S ---- fin=1 ---->C C ---- ack=1 ----> S C ---- fin=1 ----> S S ---- ack=1 ----> C
應用層由來:用戶使用的都是應用程序,均工做於應用層,互聯網是開發的,你們均可以開發本身的應用程序,數據多種多樣,必須規定好數據的組織形式
應用層功能:規定應用程序的數據格式。
例:TCP協議能夠爲各類各樣的程序傳遞數據,好比Email、WWW、FTP等等。那麼,必須有不一樣協議規定電子郵件、網頁、FTP數據的格式,這些應用程序協議就構成了」應用層」。
什麼是網絡?
一、物理鏈接介質;
二、互聯網協議。
MAC+IP:定位全世界一臺獨一無二的計算機
MAC+IP+PORT:定位全世界一臺獨一無二的計算機上的程序
但在程序中,由於操做系統配備了ARP協議,可實現IP和MAC的轉換
總結:所以【IP+PORT】便可定位定位全世界一臺獨一無二的計算機上的程序


TCP UDP TCP與UDP基本區別 1.基於鏈接與無鏈接 2.TCP要求系統資源較多,UDP較少; 3.UDP程序結構較簡單 4.流模式(TCP)與數據報模式(UDP); 5.TCP保證數據正確性,UDP可能丟包 6.TCP保證數據順序,UDP不保證 UDP應用場景: 1.面向數據報方式 2.網絡數據大多爲短消息 3.擁有大量Client 4.對數據安全性無特殊要求 5.網絡負擔很是重,但對響應速度要求高 具體編程時的區別 1.socket()的參數不一樣 2.UDP Server不須要調用listen和accept 3.UDP收發數據用sendto/recvfrom函數 4.TCP:地址信息在connect/accept時肯定 5.UDP:在sendto/recvfrom函數中每次均 需指定地址信息 6.UDP:shutdown函數無效 編程區別 一般咱們在說到網絡編程時默認是指TCP編程,即用前面提到的socket函數建立一個socket用於TCP通信,函數參數咱們一般填爲SOCK_STREAM。即socket(PF_INET, SOCK_STREAM, 0),這表示創建一個socket用於流式網絡通信。 SOCK_STREAM這種的特色是面向鏈接的,即每次收發數據以前必須經過connect創建鏈接,也是雙向的,即任何一方均可以收發數據,協議自己提供了一些保障機制保證它是可靠的、有序的,即每一個包按照發送的順序到達接收方。 而SOCK_DGRAM這種是User Datagram Protocol協議的網絡通信,它是無鏈接的,不可靠的,由於通信雙方發送數據後不知道對方是否已經收到數據,是否正常收到數據。任何一方創建一個socket之後就能夠用sendto發送數據,也能夠用recvfrom接收數據。根本不關心對方是否存在,是否發送了數據。它的特色是通信速度比較快。你們都知道TCP是要通過三次握手的,而UDP沒有。 基於上述不一樣,UDP和TCP編程步驟也有些不一樣,以下: TCP: TCP編程的服務器端通常步驟是: 一、建立一個socket,用函數socket(); 二、設置socket屬性,用函數setsockopt(); * 可選 三、綁定IP地址、端口等信息到socket上,用函數bind(); 四、開啓監聽,用函數listen(); 五、接收客戶端上來的鏈接,用函數accept(); 六、收發數據,用函數send()和recv(),或者read()和write(); 七、關閉網絡鏈接; 八、關閉監聽; TCP編程的客戶端通常步驟是: 一、建立一個socket,用函數socket(); 二、設置socket屬性,用函數setsockopt();* 可選 三、綁定IP地址、端口等信息到socket上,用函數bind();* 可選 四、設置要鏈接的對方的IP地址和端口等屬性; 五、鏈接服務器,用函數connect(); 六、收發數據,用函數send()和recv(),或者read()和write(); 七、關閉網絡鏈接; UDP: 與之對應的UDP編程步驟要簡單許多,分別以下: UDP編程的服務器端通常步驟是: 一、建立一個socket,用函數socket(); 二、設置socket屬性,用函數setsockopt();* 可選 三、綁定IP地址、端口等信息到socket上,用函數bind(); 四、循環接收數據,用函數recvfrom(); 五、關閉網絡鏈接; UDP編程的客戶端通常步驟是: 一、建立一個socket,用函數socket(); 二、設置socket屬性,用函數setsockopt();* 可選 三、綁定IP地址、端口等信息到socket上,用函數bind();* 可選 四、設置對方的IP地址和端口等屬性; 五、發送數據,用函數sendto(); 六、關閉網絡鏈接; TCP和UDP是OSI模型中的運輸層中的協議。TCP提供可靠的通訊傳輸,而UDP則常被用於讓廣播和細節控制交給應用的通訊傳輸。 UDP補充: UDP不提供複雜的控制機制,利用IP提供面向無鏈接的通訊服務。而且它是將應用程序發來的數據在收到的那一刻,馬上按照原樣發送到網絡上的一種機制。即便是出現網絡擁堵的狀況下,UDP也沒法進行流量控制等避免網絡擁塞的行爲。此外,傳輸途中若是出現了丟包,UDO也不負責重發。甚至當出現包的到達順序亂掉時也沒有糾正的功能。若是須要這些細節控制,那麼不得不交給由採用UDO的應用程序去處理。換句話說,UDP將部分控制轉移到應用程序去處理,本身卻只提供做爲傳輸層協議的最基本功能。UDP有點相似於用戶說什麼聽什麼的機制,可是須要用戶充分考慮好上層協議類型並製做相應的應用程序。 TCP補充: TCP充分實現了數據傳輸時各類控制功能,能夠進行丟包的重發控制,還能夠對次序亂掉的分包進行順序控制。而這些在UDP中都沒有。此外,TCP做爲一種面向有鏈接的協議,只有在確認通訊對端存在時纔會發送數據,從而能夠控制通訊流量的浪費。TCP經過檢驗和、序列號、確認應答、重發控制、鏈接管理以及窗口控制等機制實現可靠性傳輸。 TCP與UDP區別總結: 一、TCP面向鏈接(如打電話要先撥號創建鏈接);UDP是無鏈接的,即發送數據以前不須要創建鏈接 二、TCP提供可靠的服務。也就是說,經過TCP鏈接傳送的數據,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保 證可靠交付 三、TCP面向字節流,其實是TCP把數據當作一連串無結構的字節流;UDP是面向報文的 UDP沒有擁塞控制,所以網絡出現擁塞不會使源主機的發送速率下降(對實時應用頗有用,如IP電話,實時視頻會議等) 四、每一條TCP鏈接只能是點到點的;UDP支持一對一,一對多,多對一和多對多的交互通訊 五、TCP首部開銷20字節;UDP的首部開銷小,只有8個字節 六、TCP的邏輯通訊信道是全雙工的可靠信道,UDP則是不可靠信道
TCP套接字工做流程:
套接字程序編碼:
一、client.connect() ----》server.accept(),此過程就實現封裝三次握手過程
二、服務器端的conn套接字對象起到收發消息的做用,便可收消息,可發消息
socket服務端(單步)詳細步驟說明:


1 import socket 2 3 # 買電話 4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 5 # 默認socket.AF_INET 6 # socket.SOCK_STREAM稱爲流式協議(TCP),socket.SOCK_DGRAM爲UDP協議 7 8 # 插手機卡 9 phone.bind(('127.0.0.1',8080)) # 手機卡里面關鍵是綁定本身的手機號,教室IP:192.168.12.112,端口,0-65535,0-1024給系統用 10 11 # 開機 12 phone.listen(5) # 同一時間請求數,開啓半連接池,之後通常都是寫在配置文件裏,並非只能創建5個連接, 13 print('start...') 14 15 # 等電話連接 16 conn,client_addr = phone.accept() # conn,套接字的收發消息對象,客戶端client_addr(隨機變) 17 print('連接來了:',conn,client_addr) 18 19 # 收發消息 20 msg = conn.recv(1024) #收消息,1024是一個最大的限制,這裏假設不超過1024的狀況 21 print('客戶端的消息:',msg) 22 conn.send(msg.upper()) 23 24 # 掛電話 25 conn.close() #回收系統資源,跟打開文件後關閉文件是一個道理 26 27 # 關機 28 phone.close()
服務端Sever(循環):


1 import socket 2 3 # 買電話 4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 5 6 # 插手機卡 7 phone.bind(('127.0.0.1',8081)) 8 9 # 開機 10 phone.listen(5) 11 print('start...') 12 # 連接循環 13 while True: 14 conn,client_addr = phone.accept() 15 print('客戶端:',client_addr) 16 17 # 收發消息,通訊循環 18 while True: 19 try: 20 msg = conn.recv(1024) #收消息,1024是一個最大的限制,這裏假設不超過1024的狀況 21 print('客戶端的消息:',msg) 22 conn.send(msg.upper()) 23 except ConnectionResetError: 24 break # 此刻異常出現,conn是無心義對象,故不可用continue,而採用break 25 26 conn.close() 27 # 運行至此步,進行下一步連接 28 29 phone.close()
客戶端Client:
(補充:程序結束後,回收程序資源的同時也要回收系統資源。最後應補充一段代碼:client.close())


1 import socket 2 3 # 買電話 4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 5 6 # 撥電話,服務端IP和端口 7 phone.connect(('127.0.0.1',8081)) 8 9 # 發消息 10 while True: 11 12 msg = input('>>>:').strip() 13 phone.send(msg.encode('utf-8')) 14 # 收消息 15 data = phone.recv(1024) 16 print(data.decode('utf-8'))
編寫C/S架構的程序,實現遠程執行命令:
#subprocess使用當前系統默認編碼,獲得結果爲bytes類型,在windows下須要用gbk解碼


1 import socket 2 import subprocess 3 4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 5 phone.bind(('127.0.0.1',8082)) 6 phone.listen(5) 7 print('連線中...') 8 9 while True: 10 conn,client_addr = phone.accept() 11 print('創建鏈接客戶端:',client_addr) 12 13 while True: 14 try: 15 cmd = conn.recv(1024) 16 print('客戶端的消息:',cmd.decode('utf-8')) 17 obj = subprocess.Popen(cmd.decode('utf-8'), 18 shell=True, 19 stdout=subprocess.PIPE, 20 stderr=subprocess.PIPE 21 ) 22 stdout = obj.stdout.read() # 成功結果 23 stderr = obj.stderr.read() # 錯誤結果 24 25 conn.send(stdout+stderr) 26 27 except ConnectionResetError: 28 print('一個客戶端停止連接') 29 break 30 conn.close() 31 32 phone.close()


1 import socket 2 import subprocess 3 4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 5 phone.connect(('127.0.0.1',8082)) 6 7 8 while True: 9 cmd = input('請輸入通訊內容>>:').strip() 10 11 phone.send(cmd.encode('utf-8')) 12 msg = phone.recv(1024) 13 print(msg.decode('gbk')) # 服務器端返回命令行內容,需gbk解碼 14 15 phone.close()
這裏,會出現一個問題,當命令執行結果大於1024字節時,會有消息冗餘問題。
在找到解決方案前,需瞭解,無論收發,其實數據都是先要通過應用程序內存和操做系統緩存的處理過程。
其次,tcp流協議有兩個特色:
1,像水流同樣,源源不斷從源頭向對方堆砌數據
2,negal算法:優化數據傳輸,將時間間隔比較短和數據比較小的數據預留
那麼,如今只要知道對方要發多少數據,那麼我就能知道如何判斷是否收到所有數據
在此以前補充一下,使用stuct模塊可高度定製化的報頭數據
最後,解決粘包的方法見下:


1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 # @Time : 2018/04/19 14:03 4 # @Author : MJay_Lee 5 # @File : Server.py 6 # @Contact : limengjiejj@hotmail.com 7 8 import socket 9 import subprocess 10 import struct 11 import json 12 13 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 14 phone.bind(('127.0.0.1',8082)) 15 phone.listen(5) 16 print('連線中...') 17 18 while True: 19 conn,client_addr = phone.accept() 20 print('創建鏈接客戶端:',client_addr) 21 22 while True: 23 try: 24 cmd = conn.recv(1024) 25 print('客戶端的消息:',cmd.decode('utf-8')) 26 obj = subprocess.Popen(cmd.decode('utf-8'), 27 shell=True, 28 stdout=subprocess.PIPE, 29 stderr=subprocess.PIPE 30 ) 31 stdout = obj.stdout.read() # 成功結果 32 stderr = obj.stderr.read() # 錯誤結果 33 34 print(len(stdout)+len(stderr)) # 打印出服務器端返回消息的長度 35 # conn.send(stdout+stderr) 36 37 38 #一、發送數據長度,發送數據長度,製做報頭 39 header_dic = { 40 'total_size':len(stdout) + len(stderr), 41 'md5':'asdasdqasdasd', 42 'filename':'test.txt' 43 } 44 header_json = json.dumps(header_dic) 45 header_bytes = header_json.encode('utf-8') 46 47 # 2 先發送報頭的長度 48 header_size = len(header_bytes) 49 conn.send(struct.pack('i',header_size)) 50 51 #三、發送報頭 52 conn.send(header_bytes) 53 54 #四、發送真實數據 55 conn.send(stdout) 56 conn.send(stderr) 57 58 except ConnectionResetError: 59 print('一個客戶端停止連接') 60 break 61 conn.close() 62 phone.close()


1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 # @Time : 2018/04/19 14:03 4 # @Author : MJay_Lee 5 # @File : Client.py 6 # @Contact : limengjiejj@hotmail.com 7 8 import socket 9 import subprocess 10 import struct 11 import json 12 13 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 14 client.connect(('127.0.0.1',8082)) 15 16 17 while True: 18 cmd = input('請輸入通訊內容>>:').strip() 19 client.send(cmd.encode('utf-8')) 20 #一、先收報頭長度 21 header_size = struct.unpack('i',client.recv(4))[0] 22 #二、接收報頭 23 header_bytes = client.recv(header_size) 24 #三、解析報頭 25 header_json = header_bytes.decode('utf-8') 26 header_dic = json.loads(header_json) 27 print(header_dic) 28 29 30 total_size = header_dic['total_size'] 31 print(total_size) 32 #四、根據報頭內的信息,收取真實的數據 33 recv_size = 0 34 res = b'' 35 while recv_size < total_size: 36 recv_data = client.recv(1024) 37 res += recv_data 38 recv_size += len(recv_data) 39 print(res.decode('gbk')) 40 41 client.close()
補充:客戶端鏈接個數超出服務器設置的backlog值,出現:「ConnectionRefusedError: [WinError 10061] 因爲目標計算機積極拒絕,沒法鏈接。」,解決方案以下「優化客戶端終極版」


1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 # @Time : 2018/04/23 14:08 4 # @Author : MJay_Lee 5 # @File : client.py 6 # @Contact : limengjiejj@hotmail.com 7 8 import socket 9 import time 10 import json 11 import struct 12 13 while True: 14 try: 15 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 16 client.connect(('127.0.0.1', 8080)) 17 break 18 except ConnectionRefusedError: 19 print('等待3秒') 20 time.sleep(3) 21 22 23 while True: 24 cmd = input('請輸入通訊內容:').strip() 25 if not cmd:continue 26 client.send(cmd.encode('utf-8')) 27 # 得到報頭長度 28 header_size = struct.unpack('i',client.recv(4))[0] 29 # 獲取報頭 30 header_bytes = client.recv(header_size) 31 # 解析報頭 32 header_json = header_bytes.decode('utf-8') 33 header_dic = json.loads(header_json) 34 35 total_size = header_dic['header_len'] 36 recv_size = 0 37 res = b'' 38 39 while recv_size < total_size: 40 recv_data = client.recv(1024) 41 res += recv_data 42 recv_size += len(recv_data) 43 44 print('來自服務器的消息:',res.decode('gbk')) 45 46 client.close()
相比較於UDP,TCP之因此可靠,是由於TCP的工做原理(每發一個數據,獲得迴應,纔會清掉系統緩存裏的數據。),而非多一個連接。
場景:多用於查詢場景,可靠性要求不高
注意:UDP協議發消息的時候,有效傳輸最大51bytes,不然就容易出現丟包
套接字常識:WEB服務端端口80,DNS端口53
三個狀態