網路程式設計
引言 本篇檔案研究的網路程式設計是指基於網路編寫程式碼 能夠實現資料的遠端互動。實現資料的遠端互動必備的基礎條件是物理連線媒介 比如網路卡、網線、電話線。
一、OSI七層協定
OSI (Open System Interconnect ,開放式系統互連)七層協定:規定了所有的計算機在遠端資料互動的時候必須經過相同的處理流程、在製造過程中必須擁有相同的功能硬體。接受網路訊息 資料由下往上傳遞、傳送網路訊息 資料由上往下傳遞。OSI七層協定口訣為:應、表、會、傳、網、數、物,常見的是整合之後的五層或四層。
應用層、表示層、對談層、傳輸層、網路層、資料鏈路層、物理連結層(七層)
應用層、傳輸層、網路層、資料鏈路層、物理連結層(五層) (核心)
應用層、傳輸層、網路層、網路介面層(四層)
# 網路相關專業名詞(基礎儲備知識)
'交換機':能夠將所有接入交換機的計算機彼此互聯起來
'廣播':首次查詢接入同一個交換機的其他計算機需要朝交換機裡面吼一嗓子
'單播':首次被查詢的計算機迴應查詢它的計算機並附帶自己的mac地址
'廣播風暴':接入同一臺交換機的多型計算機同時發廣播
'區域網':有單個交換機組成的網路 在區域網內可以直接使用mac地址通訊
'廣域網':可以理解為範圍更大的區域網
'網際網路':由區域網、廣域網連線到一起形成的網路
'路由器':用來連結不同的區域網計算機的媒介
建立物理連結媒介
# 規定了電訊號的分組方式
# 乙太網協定
規定了計算機在出廠的時候都必須有一塊網路卡 網路卡上有一串數位
該數位相當於是計算機的身份證號碼是獨一無二的
該數位的特徵:12位元16進位制資料(前6位產商編號 後6位流水線號)
該數位也稱為:乙太網地址/MAC地址
IP協定:規定了所有接入網際網路的計算機都必須有一個IP地址 類似於身份證號
mac地址是實體地址可以看成永遠無法修改
IP地址是動態分配的不同的場所IP是不同的、可以用來標識全世界獨一無二的一臺計算機、可以跨區域網傳輸
IP地址特徵:
IPV4:點分十進位制
0.0.0.0
255.255.255.255
IPV6:能夠給地球上每一粒沙分一個IP地址
TCP與UDP都是用來規定通訊方式的
通訊的時候可以隨心所欲的聊 也可以遵循一些協定符合要求的聊
隨性所欲的聊:文字 圖片 視訊 小油膩話 你儂我儂
遵循一些協定:開頭帶尊稱 首行空兩格 只准用官話 不能打情罵俏
1.TCP協定(重要)
三次握手建連結
TCP協定也稱為可靠協定(資料不容易丟失)
造成資料不容易丟失的原因不是因為有雙向通道 而是因為有反饋機制
給對方發訊息之後會保留一個副本 直到對方迴應訊息收到了才會刪除
否則會在一定的時間內反覆傳送
洪水攻擊同一時間有大量的使用者端請求建立連結 會導致伺服器端一致處於SYN_RCVD狀態
伺服器端如何區分使用者端建立連結的請求 可以對請求做唯一標識
四次揮手斷連結
四次不能合併為三次 因為中間需要確認訊息是否發完(TIME_WAIT)
2.UDP協定
也稱之為資料包協定、不可靠協定
早期的QQ使用的是純生的(沒有加任何額外功能)UDP協定
現在的QQ自己新增了很多技術和功能
使用UDP的原因就是因為很簡單 快捷 粗暴 只要指定對方的地址就可以發訊息了
# PORT協定(埠協定)
用來標識一臺計算機上面的某一個應用程式
範圍:0-65535
特徵:動態分配(洗浴中心號碼牌)
建議:
0-1024 系統預設需要使用
1024-8000 常見軟體的埠號
8000之後的
URL:統一資源定位符(網址)
網址本質是有IP和PORT組成的!!!
IP+PORT:能夠定位全世界獨一無二的一臺計算機上面的某一個應用程式
域名解析:將網址解析成IP+PORT
我們之所以不直接使用IP+PORT的原因是太難記 所以發明了域名(網址)
IP:PORT 實際使用冒號連線
114.55.205.139:80
對談層提供的服務是應用建立和維持對談,並能使對談獲得同步。對談層使用校驗點可使通訊對談在通訊失效時從校驗點繼續恢復通訊。這種能力對於傳送大的檔案極為重要。對談層,表示層,應用層構成開放系統的高3層,面向應用程序提供分佈處理、對話管理、資訊表示、檢查和恢復與語意上下文有關的傳送差錯等。為給兩個對等對談服務使用者建立一個對談連線。
表示層的作用之一是為異種機通訊提供一種公共語言,以便能進行互操作。這種型別的服務之所以需要,是因為不同的電腦架構使用的資料表示法不同。例如,IBM主機使用EBCDIC編碼,而大部分PC機使用的是ASCII碼。在這種情況下,便需要對談層來完成這種轉換。通過前面的介紹,我們可以看出,對談層以下5層完成了端到端的資料傳送,並且是可靠的、無差錯的傳送。但是資料傳送只是手段而不是目的,最終是要實現對資料的使用。由於各種系統對資料的定義並不完全相同,最易明白的例子是鍵盤——其上的某些鍵的含義在許多系統中都有差異。這自然給利用其它系統的資料造成了障礙。表示層和應用層就擔負了消除這種障礙的任務。
應用層相當於是程式設計師自己寫的應用程式 裡面的協定非常的多
常見的有:HTTP、HTTPS、FTP
二、socket模組
如果我們需要編寫基於網路進行資料互動的程式,意味著需要自己通過程式碼來控制之前所學的OSI七層協定。但是過程很繁瑣、操作非常複雜、就相當於自己編寫作業系統。所以socket模組也叫通訊端出場了,它類似於作業系統,封裝了醜陋的複雜介面提供了快捷的介面。
基於檔案型別的通訊端家族(單機) AF_UNIX;
基於網路型別的通訊端家族(聯網) AF_INET;
# 伺服器端
import socket
# 1.首先要產生socket物件並指定採用的通訊版本和協定,括號內空預設是TCP協定
server = socket.socket()
# 2.繫結一個固定的地址(伺服器端必備的條件),第一個引數為本機迴環地址只能本機才能存取
server.bind(('127.0.0.1', 8080))
# 3.設立板連線池
server.listen(5)
# 4.等待接客 三次握手 sock是雙向通道 addr是使用者端地址
sock, addr = server.accept()
print(sock, addr)
# 5.服務客人 一次性接受1024位元組 傳送的資訊必須是bytes型別
data = sock.recv(1024)
print(data.decode('utf8'))
sock.send('Hello,what can do for you?'.encode('utf8'))
# 6.關閉雙向通道 就相當於門店打烊了 四次揮手
sock.close()
# 7.關閉伺服器端 就相當於門店倒閉了
server.close()
# 使用者端
import socket
# 1.首先生成socket物件指定型別和協定
client = socket.socket()
# 2.通過伺服器端的地址連結伺服器端
client.connect(('127.0.0.1', 8080))
# 3.直接給伺服器端傳送資訊
client.send('Hi,I need ur help'.encode('utf8'))
# 4.接受伺服器端傳送的資訊
data = client.recv(1024)
print(data.decode('utf8'))
# 5.斷開與伺服器端的連結
client.close()
三、並行程式設計理論
一、穿孔卡片;計算機很龐大 使用很麻煩 一次只能給一個人使用 期間很多時候計算機都不工作。這樣好處就是程式設計師獨佔計算機為所欲為、反而壞處就是計算機利用率降低 浪費資源。
二、聯機批次處理系統;提前使用磁帶一次性錄入多個程式設計師的程式然後交給計算機處理,這樣CPU工作效率提升了不用反覆等待程式錄入。
三、離線批次處理系統;極大的提升了CPU的利用率,總體而言,整個發展過程只做一件事情,那就是不斷想辦法提升CPU的利用率。所以毫無疑問,計算機中真正工作的部分是CPU。
研究躲到技術前,我們先說一下單道技術(排隊執行);即上面所討論過,所有的程式排序執行過程中不能重合,然而我們的多道技術利用計算機空閒時間提前準備其他資料最大化提升CPU的利用率。接下來咱們詳細討論一下多道技術(並行效果)。
一、切換;計算機的CPU在兩種情況下會切換,程式有IO操作即輸入輸出,input、time.sleep、read、write。我們儘可能的讓CPU同時執行多個程式。
二、儲存狀態;CPU每次切換走之前都需要儲存當前的操作狀態下次切換回來基於上次記錄繼續執行
程式:一堆死程式碼(還沒被執行)
程序:正在執行的程式(被執行的程式碼) 是資源單位表示一塊記憶體空間
執行緒:是執行單位 表示真正的程式碼指令
程序的排程演演算法
一、FCFS(first come first serve,先來先服務);對短作業不友好
二、短作業優先排程;對長作業不友好
三、時間片輪轉法加多級反饋佇列(目前還在使用);將時間均分然後根據繼承時間的長短再分多個等級,等級越靠下表示耗時越長、每次分到的時間越多但是優先順序越低。
並行;多個程序同時執行必須要多個CPU參與單個CPU無法實現並行
並行;多個程序看上去像同時執行單個CPU可以實現多個CPU也肯定可以
一、就緒態;所有的程序在被CPU執行之前都必須先進入就緒狀態等待
二、執行態;CPU正在執行
三、阻塞態;程序執行過程中出現了IO操作阻塞態無法直接進入執行態需要先進入就緒態
同步;提交完成任務之後原地等待任務的返回結果期間不做任何事情
非同步;提交完成任務之後不會原地等待返回結果直接去做其他事情有結果自動通知
阻塞;阻塞態
非阻塞;就緒態、執行態
綜合使用;有四種狀態,同步阻塞、同步非阻塞、非同步阻塞、非同步非阻塞(效率最高)
"""
1.滑鼠雙擊軟體圖示
2.Python程式碼建立程序
"""
from multiprocessing import Process
import time
class MyProcess(Process):
def __init__(self, name, age):
super().__init__()
self.name = name
self.age = age
def run(self):
print('run is running', self.name, self.age)
time.sleep(3)
print('run is over', self.name. self.age)
if __name__ == '__main__':
obj = MyProcess('almira', 123)
obj.start()
print('主')
from multiprocessing import Process, current_procsee
import os
import time
# 1.檢視程序號
current_process()
current_process().pid
os.getpid()
os.getppid()
# 2.結束程序
p1.terminate()
# 3.判斷程序是否存活
p1.is_alive()
# 4.守護行程
def task(name):
print('程序名:%s' % name)
time.sleep(3)
print('程序名:%s' % name)
if __name__ == '__main__':
p1 = Process(target=task, args=('米熱',))
p1.daemon = True
p1.start()
time.sleep(1)
print('複習使我快樂')
from multiprocessing import Process
import time
import json
import random
# 查票
def search(name):
with open(r'data.json', 'r', encoding='utf8') as f:
data = json.load(f)
print('%s在查票 當前餘票為:%s' % (name, data.get('ticket_num')))
# 買票
def buy(name):
# 再次確認票
with open(r'data.json', 'r', encoding='utf8') as f:
data = json.load(f)
# 模擬網路延遲
time.sleep(random.randint(1, 3))
# 判斷是否有票 有就買
if data.get('ticket_num') > 0:
data['ticket_num'] -= 1
with open(r'data.json', 'w', encoding='utf8') as f:
json.dump(data, f)
print('%s買票成功' % name)
else:
print('%s很倒黴 沒有搶到票' % name)
def run(name):
search(name)
buy(name)
if __name__ == '__main__':
for i in range(10):
p = Process(target=run, args=('使用者%s'%i, ))
p.start()
程序和執行緒都不可以無限制的建立 因為硬體的發展速度趕不上軟體 有物理極限 如果在編寫程式碼的過程中無限制的建立程序或執行緒可能會導致計算機崩潰。
一、池;降低程式的執行效率 但是保證了計算機硬體的安全
二、程序池;提前建立好固定數量的程序供後續程式的呼叫超出則等待
三、執行緒池;提前建立好固定數量的執行緒供後續程式的呼叫超出則等待
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
import os
import time
import random
from threading import current_thread
# 1.產生含有固定數量執行緒的執行緒池
# pool = ThreadPoolExecutor(10)
pool = ProcessPoolExecutor(5)
def task(n):
print('task is running')
# time.sleep(random.randint(1, 3))
# print('task is over', n, current_thread().name)
# print('task is over', os.getpid())
return '我是task函數的返回值'
def func(*args, **kwargs):
print('from func')
if __name__ == '__main__':
# 2.將任務提交給執行緒池即可
for i in range(20):
# res = pool.submit(task, 123) # 朝執行緒池提交任務
# print(res.result()) # 不能直接獲取
# pool.submit(task, 123).add_done_callback(func)
程序;資源單位
執行緒;執行單位
協成;單執行緒下實現並行(效率極高)
下面咱細說一下協成吧!在程式碼層面欺騙CPU 讓CPU覺得我們的程式碼裡面沒有IO操作、實際上IO操作被我們自己寫的程式碼檢測一旦有立刻程式碼執行別的程式;該技術完全是程式設計師自己弄出來的名字也是程式自己起的,核心:自己寫程式碼完成切換+儲存狀態
'協成程式碼實現'
import time
from gevent import monkey;
monkey.patch_all() # 固定編寫 用於檢測所有的IO操作(猴子修補程式)
from gevent import spawn
def func1():
print('func1 running')
time.sleep(3)
print('func1 over')
def func2():
print('func2 running')
time.sleep(5)
print('func2 over')
if __name__ == '__main__':
start_time = time.time()
# func1()
# func2()
s1 = spawn(func1) # 檢測程式碼 一旦有IO自動切換(執行沒有io的操作 變向的等待io結束)
s2 = spawn(func2)
s1.join()
s2.join()
print(time.time() - start_time) # 8.01237154006958 協程 5.015487432479858
'協成實現並行'
import socket
from gevent import monkey;monkey.patch_all() # 固定編寫 用於檢測所有的IO操作(猴子修補程式)
from gevent import spawn
def communication(sock):
while True:
data = sock.recv(1024)
print(data.decode('utf8'))
sock.send(data.upper())
def get_server():
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
sock, addr = server.accept() # IO操作
spawn(communication, sock)
s1 = spawn(get_server)
s1.join()