腦圖結構
OSI 模型
腦圖結構
理解示意圖
額外補充
Socket是應用層與 TCP/IP協議族通訊的中間軟件抽象層,它是一組接口。編程
在設計模式中, Socket其實就是一個門面模式設計模式
它把複雜的 TCP/IP協議族隱藏在 Socket接口後面,對用戶來講,一組簡單的接口就是所有,讓 Socket去組織數據,以符合指定的協議。瀏覽器
server
import socket sk = socket.socket() sk.bind(('127.0.0.1',8898)) # 把地址綁定到套接字 sk.listen() # 監聽連接 conn,addr = sk.accept() # 接受客戶端連接 ret = conn.recv(1024) # 接收客戶端信息 print(ret) # 打印客戶端信息 conn.send(b'hi') # 向客戶端發送信息 conn.close() # 關閉客戶端套接字 sk.close() # 關閉服務器套接字(可選)
client
import socket sk = socket.socket() # 建立客戶套接字 sk.connect(('127.0.0.1',8898)) # 嘗試鏈接服務器 sk.send(b'hello!') ret = sk.recv(1024) # 對話(發送/接收) print(ret) sk.close() # 關閉客戶套接字
特性
粘包
額外補充
TCP (Transmission Control Protocol)可靠的、面向鏈接的協議(eg:打電話)、傳輸效率低全雙工通訊(發送緩存&接收緩存)、面向字節流。緩存
使用TCP的應用:Web瀏覽器;電子郵件、文件傳輸程序。服務器
server
import socket udp_sk = socket.socket(type=socket.SOCK_DGRAM) #建立一個服務器的套接字 udp_sk.bind(('127.0.0.1',9000)) #綁定服務器套接字 msg,addr = udp_sk.recvfrom(1024) print(msg) udp_sk.sendto(b'hi',addr) # 對話(接收與發送) udp_sk.close() # 關閉服務器套接字
client
import socket ip_port=('127.0.0.1',9000) udp_sk=socket.socket(type=socket.SOCK_DGRAM) udp_sk.sendto(b'hello',ip_port) back_msg,addr=udp_sk.recvfrom(1024) print(back_msg.decode('utf-8'),addr)
額外補充
UDP (User Datagram Protocol)不可靠的、無鏈接的服務,傳輸效率高(發送前時延小),一對1、一對多、多對1、多對多、面向報文,盡最大努力服務,無擁塞控制。網絡
使用UDP的應用:域名系統 (DNS);視頻流;IP語音(VoIP)。socket
socket概念 套接字:實現網絡編程進行數據傳輸的一種技術手段 相關模塊: import socket 分類 流式套接字(SOCK_STREAM): 以字節流方式傳輸數據,實現tcp網絡傳輸方案。 數據報套接字(SOCK_DGRAM):以數據報形式傳輸數據,實現udp網絡傳輸方案。 面向鏈接--tcp協議--可靠的--流式套接字 無鏈接--udp協議--不可靠--數據報套接字 tcp套接字編程 服務端流程 1. 建立套接字 sk = socket.socket(socket_family=AF_INET,socket_type=SOCK_STREAM,proto=0) 功能: 建立套接字 參數: socket_family 網絡地址類型 AF_INET-->ipv4 socket_type 選擇類型,與 TCP/UDP 中選擇, 默認就是 TCP 模式 套接字類型 SOCK_STREAM 流式(TCP) SOCK_DGRAM 數據報(UDP) proto 一般爲0,能夠忽略 選擇子協議 返回值: 套接字對象 2. 綁定地址 sk.bind(addr) 功能: 綁定本機網絡地址 參數: 二元元組 (ip,port) 例如:('0.0.0.0',8888) 3. 設置監聽 sk.listen(n) 功能 : 將套接字設置爲監聽套接字,肯定監聽隊列大小 參數 : 監聽隊列大小 4. 等待處理客戶端鏈接請求 conn,addr = sk.accept() 功能: 阻塞等待處理客戶端請求 返回值: conn 客戶端鏈接套接字 addr 鏈接的客戶端地址 * 阻塞函數 : 程序運行過程當中遇到阻塞函數則暫停執行,直到達成某種條件後繼續運行。 5. 消息收發 data = conn.recv(buffersize) 功能 : 接受客戶端消息 參數 :每次最多接收消息的大小 返回值: 接收到的內容 n = conn.send(data) 功能 : 發送消息 參數 :要發送的內容 bytes格式 返回值: 發送的字節數 * str --> bytes string.encode() bytes --> str bytes.decode() 6. 關閉套接字 sk.close() 功能:關閉套接字 """ import socket sk = socket.socket() sk.bind(("127.0.0.1", 8008)) sk.listen() conn, addr = sk.accept() conn.send(b"hello") conn.close() sk.close() """ 客戶端流程 1. 建立套接字 sk = socket.socket() * 只有相同類型的套接字才能進行通訊 2. 請求鏈接 sk.connect(server_addr) 功能:鏈接服務器 參數:元組 服務器地址 3. 收發消息 print(sk.recv(1024)) * 防止兩端都阻塞,recv send要配合 4. 關閉套接字 """ import socket sk = socket.socket() sk.connect(("127.0.0.1", 8008)) print(sk.recv(1024)) sk.close() """ 代碼流程總結 服務端:socket() --> bind() --> listen() --> accept() --> recv(),send() --> close() 客戶端:socket() --> connect() --> send(),recv() --> close() 總體過程總結 * tcp鏈接中當一端退出,另外一端若是阻塞在recv,此時recv會當即返回一個空字串。 * tcp鏈接中若是一端已經不存在,讓然試圖經過send發送則會產生BrokenPipeError * 一個監聽套接字能夠同時鏈接多個客戶端,也可以重複被鏈接 * 網絡收發緩衝區 【1】網絡緩衝區有效的協調了消息的收發速度 【2】send和recv實際是向緩衝區發送接收消息,當緩衝區不爲空recv就不會阻塞。 * tcp粘包 【1】 緣由:tcp以字節流方式傳輸,沒有消息邊界。屢次發送的消息被一次接收,此時就會造成粘包。 【2】 影響:若是每次發送內容是一個獨立的含義,須要接收端獨立解析此時粘包會有影響。 【3】 處理: 1. 人爲的添加消息邊界 2. 控制發送速度 UDP套接字編程 服務端流程 1. 建立數據報套接字 sk = socket(AF_INET,SOCK_DGRAM) 2. 綁定地址 sk.bind(addr) 3. 消息收發 data,addr = sockfd.recvfrom(buffersize) 功能: 接收UDP消息 參數: 每次最多接收多少字節 返回值: data 接收到的內容 addr 消息發送方地址 n = sockfd.sendto(data,addr) 功能: 發送UDP消息 參數: data 發送的內容 bytes格式 addr 目標地址 返回值:發送的字節數 4. 關閉套接字 sockfd.close() """ import socket udp_sk = socket.socket(type=socket.SOCK_DGRAM) udp_sk.bind(('127.0.0.1', 9000)) msg, addr = udp_sk.recvfrom(1024) print(msg) udp_sk.sendto(b'hi', addr) udp_sk.close() """ 客戶端流程 1. 建立套接字 sk=socket.socket(type=socket.SOCK_DGRAM) 2. 收發消息 sk.sendto(data,("127.0.0.1",8000)) sk.recvfrom(1024) 3. 關閉套接字 sk.close() """ import socket sk = socket.socket(type=socket.SOCK_DGRAM) addr = ("127.0.0.1", 9000) sk.sendto(b"hello", addr) data, addr = sk.recvfrom(1024) print(data) sk.close() """