網(wǎng)絡(luò)編程?
網(wǎng)絡(luò)目的 : 數(shù)據(jù)的傳輸
網(wǎng)絡(luò)數(shù)據(jù)傳輸是一個復(fù)雜的過程
OSI 七層模型 --》 網(wǎng)絡(luò)通信標(biāo)準(zhǔn)化流程
* 應(yīng)用層?: 提供用戶服務(wù),具體內(nèi)容由特定程序規(guī)定
* 表示層?: 數(shù)據(jù)的壓縮優(yōu)化?
* 會話層?: 建立應(yīng)用連接,選擇傳輸層服務(wù)
* 傳輸層?: 提供不同的傳輸服務(wù),流量控制
* 網(wǎng)絡(luò)層?: 路由選擇,網(wǎng)絡(luò)互連
* 鏈路層?: 提供鏈路交換,具體消息以幀發(fā)送
* 物理層?: 物理硬件,接口,網(wǎng)卡,線路
osi七層模型優(yōu)點(diǎn) : 將功能分開,降低了網(wǎng)絡(luò)傳輸中的耦合性,每一部分完成自己的功能??梢栽陂_發(fā)和實(shí)施的過程中各司其職。實(shí)現(xiàn)高內(nèi)聚和低耦合的功能。
高內(nèi)聚 : 單個模塊功能盡量單一
低耦合 : 模塊之間盡量減少關(guān)聯(lián)和影響
四層?
* 應(yīng)用層 : 應(yīng)用層 表示層 會話層
* 傳輸層 : 傳輸層
* 網(wǎng)絡(luò)層 : 網(wǎng)絡(luò)層
* 物理鏈路層: 鏈路層和物理層
五層(tcp/ip模型)
* 應(yīng)用層 : 應(yīng)用層 表示層 會話層
* 傳輸層 : 傳輸層
* 網(wǎng)絡(luò)層 : 網(wǎng)絡(luò)層
* 鏈路層 : 鏈路層
* 物理層 : 物理層
?
協(xié)議(網(wǎng)絡(luò)協(xié)議):在網(wǎng)絡(luò)通信中,各方必須遵守的規(guī)定。包括建立什么樣的連接,消息結(jié)構(gòu)等
應(yīng)用層 : TFTP HTTP DNS SMTP
傳輸層 : TCP UDP
網(wǎng)絡(luò)層 : IP?
物理層 : IEEE
?
網(wǎng)絡(luò)基本概念
1、主機(jī): "localhost" 表示本臺計算機(jī)
網(wǎng)絡(luò)上 : 只在本地測試使用
'localhost' '127.0.0.1'
如果想在網(wǎng)絡(luò)上進(jìn)行測試(自動使用本地可用網(wǎng)卡IP)
'0.0.0.0' '' '172.60.50.93'
查看本地 IP 網(wǎng)絡(luò)信息
linux上:? ? ifconfig?
win上查看本地IP: ipconfig
ping www.baidu.com? --->14.215.177.38(百度的IP地址)
獲取計算機(jī)名稱
socket.gethostname()
'tedu'
獲取主機(jī)IP
socket.gethostbyname('localhost')
'127.0.0.1'
2、IP地址
在網(wǎng)絡(luò)上用于區(qū)分一臺計算?
IPv4 : 點(diǎn)分十進(jìn)制 e.g. 192.168.1.72 0-255
32位二進(jìn)制表示
IPv6 : 128
網(wǎng)絡(luò)連接測試命令:?ping 172.60.50.92
特殊IP
127.0.0.1 本地測試IP
0.0.0.0 本地網(wǎng)卡通用IP
192.168.1.0 表示當(dāng)前網(wǎng)段
192.168.1.1 表示網(wǎng)關(guān)
192.168.1.255 廣播地址
獲取服務(wù)器主機(jī)信息
socket.gethostbyaddr("www.baidu.com")
('127.0.0.1', [], ['119.75.213.61'])
主機(jī) 別名 IP地址
將ip十進(jìn)制轉(zhuǎn)化為二進(jìn)制
socket.inet_aton("192.168.1.2")
b'\xc0\xa8\x01\x02'
將ip二進(jìn)制轉(zhuǎn)化為十進(jìn)制
socket.inet_ntoa(b"\xc0\xa8\x01\x02")
'192.168.1.2'
域名?: 網(wǎng)絡(luò)服務(wù)器IP地址的名稱
url?: 在網(wǎng)絡(luò)上定位某個資源位置
3、端口號?:端口號是網(wǎng)絡(luò)地址的一部分,在一個系統(tǒng)中每個網(wǎng)絡(luò)應(yīng)用監(jiān)聽不同的端口,以獲取對應(yīng)端口傳輸?shù)男畔?br>
數(shù)字范圍 : 1--65535
1--255 : 一些眾所周知的端口
256--1023 : 系統(tǒng)應(yīng)用
1024---65535 : 自用?
推薦用? >10000 8888 9999 7777 6666
測試一個軟件端口號
socket.getservbyname('mysql')
3306
socket.getservbyname('http')
80
socket.getservbyname('ssh')
22
傳輸層服務(wù)?
面向連接的傳輸服務(wù) ---》 tcp協(xié)議?
傳輸特征:提供可靠的傳輸服務(wù)
可靠性表現(xiàn): 數(shù)據(jù)在傳輸過程中,無失序,無差錯,無重復(fù),無丟失
* 傳輸過程中有建立和斷開連接的過程
三次握手:建立數(shù)據(jù)傳輸兩端的持續(xù)連接
1.?客戶端向服務(wù)器發(fā)起連接請求(我可以牽你手嗎)
2. 服務(wù)器收到連接請求進(jìn)行確認(rèn),返回報文(可以)
3. 客戶端收到服務(wù)器確認(rèn)進(jìn)行連接創(chuàng)建(牽手成功)
四次揮手:斷開連接的兩端,保證數(shù)據(jù)的傳輸完整
1.主動方發(fā)送報文,告知被動方要斷開連接(我們分手吧,你準(zhǔn)備好)
2.被動方返回報文,告知收到請求,準(zhǔn)備斷開(知道了)
3.被動方再次發(fā)送報文,告知準(zhǔn)備完畢可以斷開(你分手吧)
4.主動方發(fā)送報文完成斷開(分手了)
適用情況:文件的上傳下載,網(wǎng)絡(luò)情況良好,需要必須保證可靠性的情況
比如 : 信息聊天,文件上傳下載,郵件,網(wǎng)頁獲取
面向無連接的傳輸服務(wù) ---》 udp協(xié)議
傳輸特征 :
*?不保證傳輸?shù)目煽啃?br> *?無需建立三次握手和四次揮手的連接斷開過程
* 消息的收發(fā)比較自由,不受其他約束(請?jiān)徫疫@一生放蕩不羈愛自由)
適用情況 : 網(wǎng)絡(luò)情況較差,對可靠性要求不高,收發(fā)消息的兩端不適合建立固定連接
比如 :網(wǎng)絡(luò)視頻,群聊,發(fā)送廣播
套接字----socket
socket模塊的套接字屬性
(s表示一個套接字對象)
s.type 獲取套接字類型 # SocketKind.SOCK_STREAM 流式套接字
s.family 獲取地址族類型 # AddressFamily.AF_INET 獲取地址族類型
s.fileno() 獲取套接字的文件描述符(每一個IO操作系統(tǒng)都會為其分配一個不同的正整數(shù),該正整數(shù)即為此IO操作系統(tǒng)的文件描述符)
s.getsockname() 獲取套接字綁定的地址 #?('192.168.191.3', 8888)
s.getpeername() 獲取連接套接字另一端的地址 # ('192.168.191.3', 7826)
s.setsockopt(level,optname,value) 設(shè)置套接字選項(xiàng),豐富修改原有套接字功能
參數(shù): level?設(shè)置選項(xiàng)的類型 optname 每個選項(xiàng)類型中的子選項(xiàng) value 為選項(xiàng)設(shè)置值
s.getsockopt(level,optname) 獲取套接字選項(xiàng)的值
1 from socket import * 2 s = socket() 3 print(s.type) #
SocketKind.SOCK_STREAM 流式套接字 4 print(s.family) # AddressFamily.AF_INET 獲取地址族類型
5 print(s.fileno()) # 376 6 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 設(shè)置端口可重用
7 print(s.getsockopt(SOL_SOCKET,SO_REUSEADDR))# 獲取選項(xiàng)值 1 8 s.bind(("
192.168.191.3",8888)) 9 print(s.getsockname()) # 獲取綁定的地址 ('192.168.191.3',
8888) 10 s.listen() 11 c,addr = s.accept() # addr也是鏈接客戶端的地址 12 print
(c.getpeername())# ('192.168.191.3', 7826)獲取鏈接套接字客戶端地址 13 data = c.recv(1024) 14
print(data) # b'i' 15 c.close() 16 s.close() View Code
socket套接字編程
套接字:通過編程語言提供的函數(shù)接口進(jìn)行組合,更簡單的完成基于tcp和udp通信的網(wǎng)絡(luò)編程
套接字的分類
流式套接字(SOCK_STREAM):傳輸層基于tcp的協(xié)議進(jìn)行通信
數(shù)據(jù)報套接字(SOCK_DGRAM):傳輸層基于udp的協(xié)議進(jìn)行通信
底層套接字(SOCK_RAM):訪問底層協(xié)議的套接字?
網(wǎng)絡(luò)收發(fā)緩沖區(qū)
1、協(xié)調(diào)讀寫速度、減少和磁盤交互
2、recv和send實(shí)際上是從緩沖區(qū)獲取內(nèi)容,和向緩沖區(qū)發(fā)送內(nèi)容
recv()特性
1、如果連接斷開,recv會立即結(jié)束阻塞返回空字符串
2、當(dāng)接收緩存區(qū)為空時會阻塞
3、如果recv一次接收不完緩沖區(qū)內(nèi)容,下次會繼續(xù)接收,確保數(shù)據(jù)不丟失
send()特性
1、如果另一端不存在還試圖使用send進(jìn)行發(fā)送則會產(chǎn)生BrokenPipError異常
2、當(dāng)發(fā)送緩沖區(qū)滿時會阻塞
本地套接字?
作用:用于本地不同程序間的進(jìn)行數(shù)據(jù)傳輸
本地套接字的創(chuàng)建流程
1、創(chuàng)建套接字對象
sockfd = socket(AF_UNIX,SOCK_STREAM)
2、綁定本地套接字文件,如果文件不存在,則自動創(chuàng)建文件(綁定套接字文件)
sockfd.bind(file)
判斷一個文件夾下是否有某個文件 os.path.exists('./tcp_client.py')
刪除一個文件 os.remove(file) os.remove(file)
3、監(jiān)聽 listen?
4、接收發(fā)送消息 recv send
from socket import * import os sock_file = './sock' # 使用哪個文件作為套接字文件 if
os.path.exists(sock_file):# 判斷文件是否已經(jīng)存在 os.unlink(sock_file) sockfd =
socket(AF_UNIX,SOCK_STREAM)# 創(chuàng)建本地套接字 sockfd.bind(sock_file) # 綁定
sockfd.listen(5)# 監(jiān)聽 while True: c,addr = sockfd.accept() # 建立連接 while True:
data= c.recv(1024) if not data: break print(data.decode()) c.close()
sockfd.close() 服務(wù)端 from socket import * sock_file = "./sock" # 確保通信兩端用相同的套接字文件
sockfd= socket(AF_UNIX,SOCK_STREAM) # 創(chuàng)建套接字 sockfd.connect(sock_file) # 鏈接
while True: msg = input("Msg>>") if msg: sockfd.send(msg.encode()) else: break
sockfd.close() 客戶端
?
TCP粘包
產(chǎn)生原因:TCP傳輸采用字節(jié)流的方式,消息之間沒有邊界,如果發(fā)送的速度比接收速度快,會造成多次發(fā)送的內(nèi)容被一次接收,形成意義上的誤解即粘包
產(chǎn)生條件:當(dāng)使用send快速的連續(xù)發(fā)送極有可能產(chǎn)生粘包
影響:如果每次發(fā)送的內(nèi)容代表一個獨(dú)立的意思,需要單獨(dú)識別,就會產(chǎn)生粘包。但是如果多次發(fā)送的內(nèi)容就是一個連續(xù)的整體,此時就不需要處理。
如何處理:
1、每次發(fā)送后加一個結(jié)尾標(biāo)志,接收端通過標(biāo)志進(jìn)行判斷
2、發(fā)送一個數(shù)據(jù)結(jié)構(gòu)
3、每次發(fā)送中間有一個短暫的延遲(有一個間隔)
TCP接收多個客戶端連接,且可以持續(xù)發(fā)送消息
from socket import * sockfd = socket(AF_INET,SOCK_STREAM) #創(chuàng)建套接字 sockfd.bind((
'127.0.0.1',9999)) #綁定地址 sockfd.listen(5) #設(shè)置監(jiān)聽 while True: # 等待客戶端連接 print("
Waiting for connect...") connfd,addr = sockfd.accept() print("Connect from"
,addr)while True: # 消息收發(fā) data = connfd.recv(1024) if not data: break print("
Receive:",data.decode()) n = connfd.send(b"Receive your message") print("send
%d bytes"%n) connfd.close() # 關(guān)閉套接字 sockfd.close() TCP-server from socket
import * sockfd = socket() #創(chuàng)建套接字 sockfd.connect(('127.0.0.1',9999)) #發(fā)起連接
while True: #消息收發(fā) msg = input("Msg>>") if not msg: break
sockfd.sendall(msg.encode()) data= sockfd.recv(1024) print(data.decode())
sockfd.close() TCP-client
HTTP
http協(xié)議-->超文本傳輸協(xié)議? 應(yīng)用層協(xié)議,HTTP是基于TCP協(xié)議編碼的。
用途:網(wǎng)頁的獲取,基于網(wǎng)站的數(shù)據(jù)傳輸,基于http協(xié)議的數(shù)據(jù)傳輸
特點(diǎn)
* 應(yīng)用層協(xié)議。傳輸層使用TCP傳輸
* 無狀態(tài)協(xié)議,不記錄用戶的通信內(nèi)容
* http1.1---->http2.0 成熟穩(wěn)定
工作模式:
使用http雙方均遵守http協(xié)議規(guī)定發(fā)送接收消息體
請求方,根據(jù)協(xié)議組織請求內(nèi)容給對象
服務(wù)方,收到內(nèi)容按照協(xié)議解析
服務(wù)方,將回復(fù)內(nèi)容按照協(xié)議組織發(fā)送給請求方
請求方,收到回復(fù)根據(jù)協(xié)議解析
HTTP請求格式
格式:?請求行\(zhòng) 請求頭\ 空行\(zhòng) 請求體
1、請求行(熟悉格式及作用):?提供具體的請求類別, 請求內(nèi)容
GET / index.html / HTTP/1.1
請求類別 請求內(nèi)容 ? 協(xié)議版本
請求種類 :? ?GET 獲取網(wǎng)絡(luò)資源
POST 提交一定的附加數(shù)據(jù),得到返回 結(jié)果
HEAD 獲取響應(yīng)頭
PUT 更新服務(wù)器資源
DELETE 刪除服務(wù)器資源
CONNECT 預(yù)留
TRACE 測試
OPTIONS 獲取服務(wù)器性能
2、請求頭 : 對請求內(nèi)容的具體描述,?以鍵值對的形式對請求信息進(jìn)行描述
e.g.
Accept: text/html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
3、空行
4、請求體?: 具體的請求參數(shù)
(GET參數(shù),或者POST提交的內(nèi)容)
HTTP響應(yīng)格式
1、響應(yīng)行 反饋具體的響應(yīng)情況
HTTP/1.1 200 OK
版本信息 響應(yīng)碼 ?附加信息
響應(yīng)碼 :
* 1xx 提示信息 表示請求已經(jīng)接受
* 2xx 響應(yīng)成功
* 3xx 響應(yīng)需要重新請定向
* 4xx 客戶端錯誤
* 5xx 服務(wù)器錯誤
常見響應(yīng)碼 :
* 200 成功
* 404 請求頁面不存在
* 401 沒有訪問權(quán)限
* 500 服務(wù)器發(fā)生未知錯誤
* 503 服務(wù)器暫時無法執(zhí)行
2、響應(yīng)頭 對響應(yīng)信息的具體描述
e.g.
Cache-Control: private
Connection: Keep-Alive
3、空行
4、響應(yīng)體:將客戶想要的內(nèi)容進(jìn)行返回
搭建HTTP本地服務(wù)器?
做的是一個本地服務(wù)端,接收來自瀏覽器客戶端的請求
# 返回第一行 GET / HTTP/1.1
* 接收http請求; 解析http請求
* 響應(yīng)一個網(wǎng)頁給客戶端 from socket import * # 處理客戶端請求 def handle(connfd): request =
connfd.recv(4096)# 接收請求 # 防止客戶端斷開request為空 if not request: return request_line
= request.splitlines()[0]# 返回第一行 GET / HTTP/1.1 info =
request_line.decode().split(' ')[1] if info == '/': with open('index.html') as
f: response= "HTTP/1.1 200 OK\r\n" # 響應(yīng)行 response += "Content-Type:text/html\r\n
" # 響應(yīng)頭 response += '\r\n' # 空行 response += f.read() # 響應(yīng)體 else: response = "
HTTP/1.1 404 Not Found\r\n" response += "Content-Type:text/html\r\n" response +=
'\r\n' response += "<h1>Sorry...</h1>" connfd.send(response.encode()) # 發(fā)送給瀏覽器
sockfd= socket() # 搭建tcp網(wǎng)絡(luò) sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sockfd.bind(('0.0.0.0',8000)) # 綁定地址 sockfd.listen(3) # 設(shè)置監(jiān)聽 while True:
connfd,addr= sockfd.accept() # 獲取連接端和地址 handle(connfd) # 處理客戶端請求
?在瀏覽器輸入地址:127.0.0.1:8888,即可得到網(wǎng)頁顯示!
?
熱門工具 換一換