1.TCP協議與UDP協議
TCP(Transmission Control Protocol,傳輸控制協議)和 UDP(User Datagram Protocol,用戶數據報協議)是 TCP/IP 協議族中兩種核心的傳輸層協議,它們在數據傳輸方式、可靠性、適用場景等方面有顯著區別。
1、核心區別對比
特性 | TCP | UDP |
---|---|---|
連接方式 | 面向連接(需先建立連接) | 無連接(直接發送數據) |
可靠性 | 可靠傳輸(保證數據完整、有序到達) | 不可靠傳輸(不保證送達,可能丟失) |
傳輸效率 | 較低(需處理確認、重傳等機制) | 較高(無額外控制開銷) |
數據邊界 | 無(流式傳輸,需應用層處理邊界) | 有(以數據報為單位,一次發送一個完整報文) |
擁塞控制 | 支持(避免網絡擁堵) | 不支持 |
首部開銷 | 較大(固定 20 字節,可擴展) | 較小(固定 8 字節) |
適用場景 | 文件傳輸、網頁瀏覽、郵件等 | 視頻通話、實時游戲、廣播等 |
2、TCP 協議詳解
1. 核心特點:面向連接、可靠傳輸
連接建立:通過 “三次握手” 建立連接(類似打電話確認雙方可通信)
- 客戶端發送 SYN(請求連接)
- 服務器回復 SYN+ACK(同意連接)
- 客戶端回復 ACK(確認連接建立)
可靠傳輸機制:
- 序號與確認機制:每個數據包有編號,接收方收到后需返回確認(ACK),未確認則重傳
- 重傳機制:發送方超時未收到確認則重傳數據
- 流量控制:通過滑動窗口限制發送速率,避免接收方緩沖區溢出
- 擁塞控制:根據網絡狀況動態調整發送速率(慢啟動、擁塞避免等算法)
連接終止:通過 “四次揮手” 關閉連接(確保雙方數據都已傳輸完畢)
2. 工作流程示例(文件傳輸)
- 客戶端向服務器發起連接請求(三次握手)
- 連接建立后,客戶端分塊發送文件數據
- 服務器每收到一塊數據就返回確認
- 若某塊數據丟失,客戶端超時后重傳
- 所有數據傳輸完成,雙方通過四次揮手關閉連接
3. 優缺點
- 優點:數據可靠、有序,適合對準確性要求高的場景
- 缺點:延遲較高(握手、確認等耗時),開銷大
3、UDP 協議詳解
1. 核心特點:無連接、不可靠傳輸
- 無連接:發送數據前無需建立連接,直接封裝數據并發送(類似郵寄信件)
- 不可靠:
- 不保證數據送達(無確認機制)
- 不保證順序(數據包可能亂序到達)
- 不處理重傳(丟失數據需應用層自行處理)
- 數據報傳輸:每個 UDP 報文獨立發送,接收方一次讀取一個完整報文
2. 工作流程示例(視頻通話)
- 客戶端直接向服務器發送視頻幀數據(無需提前建立連接)
- 服務器收到數據后直接交給應用層處理
- 若部分數據包丟失,應用層可選擇忽略(避免卡頓)或請求重傳關鍵幀
- 通信結束無需 “關閉連接”,直接停止發送即可
3. 優缺點
- 優點:傳輸速度快、延遲低、開銷小,適合實時性要求高的場景
- 缺點:數據可能丟失、亂序,需應用層自行處理可靠性
4、適用場景對比
協議 | 典型應用 | 選擇原因 |
---|---|---|
TCP | 網頁(HTTP/HTTPS)、文件傳輸(FTP)、郵件(SMTP) | 需保證數據完整、準確,允許一定延遲 |
UDP | 視頻通話(如 Zoom)、實時游戲、DNS 查詢、廣播 | 需低延遲,可容忍少量數據丟失 |
總結:TCP就像打電話,需要先接通,建立聯系,確保雙方能同時接收或發送數據,而UDP更像送快遞,雖然速度快,但是會有數據丟失的風險.
2.IP地址
1.IP地址的概念
IP 地址(Internet Protocol Address,互聯網協議地址)是互聯網中用于唯一標識網絡設備(如計算機、路由器、服務器、手機等)的數字標簽,相當于設備在網絡中的 “門牌號碼”。所有網絡通信(如瀏覽網頁、發送消息、下載文件)都依賴 IP 地址來定位目標設備,確保數據能準確從 “發送方” 傳輸到 “接收方”。
一、核心作用:定位與路由
IP 地址的核心功能可拆解為兩點:
- 設備標識:在全球或局部網絡中,每個設備的 IP 地址具有唯一性(同一網絡內絕對唯一,全球范圍內通過路由規則確保不沖突),避免數據傳錯目標。
- 路由指引:數據在網絡中傳輸時,路由器會根據 IP 地址中的 “網絡段” 信息,判斷數據應轉發到哪個子網,最終導向目標設備(類似快遞根據 “省 - 市 - 區” 分層投遞)。
二、IP 地址的兩大版本:IPv4 與 IPv6
目前主流的 IP 地址分為兩個版本,核心差異在于地址長度、容量和格式,本質是為解決 “地址耗盡” 問題(IPv4 地址不夠用)。
對比維度 IPv4(互聯網協議第 4 版) IPv6(互聯網協議第 6 版) 地址長度 32 位(二進制) 128 位(二進制) 地址格式 點分十進制(如? 192.168.1.1
)冒分十六進制(如? 2001:0db8:85a3:0000:0000:8a2e:0370:7334
)地址容量 約 42.9 億個(232),已基本耗盡 約 3.4×103?個(212?),足夠支撐未來百年 配置方式 需手動配置或 DHCP 自動分配 支持自動配置(無狀態地址自動配置 SLAAC) 安全性 無內置安全機制,需依賴 TCP 或應用層(如 SSL) 內置 IPsec 協議,原生支持加密和身份驗證 主流程度 目前仍廣泛使用(占比超 90%) 逐步推廣(物聯網、5G 場景優先部署) 三、IPv4 地址的結構與分類(重點)
IPv4 是目前最常用的版本,其 32 位地址分為 “網絡位” 和 “主機位” 兩部分:
- 網絡位:標識設備所屬的 “子網”(類似 “小區地址”);
- 主機位:標識子網內的具體設備(類似 “小區內的門牌號”)。
為區分網網絡位,后 8 位是主機位)。
1. IPv4 地址的分類(傳統分類,便于初期管理)
IPv4 根據首段數字(第 1 個十進制數)分為 5 類,其中 A、B、C 類為 “單播地址”(用于單個設備通信絡位和主機位,IPv4 通過子網掩碼(Subnet Mask)?標記(如?
255.255.255.0
?表示前 24 位是),D 類為 “組播地址”(一對多通信,如視頻會議),E 類為 “保留地址”(未公開使用)。
地址類別 首段數字范圍 網絡位長度 主機位長度 適用場景 示例 A 類 1~126 8 位 24 位 大型網絡(如早期互聯網主干) 10.0.0.1
(私有地址)B 類 128~191 16 位 16 位 中型網絡(如企業內網) 172.16.0.1
(私有)C 類 192~223 24 位 8 位 小型網絡(如家庭 / 辦公室) 192.168.1.1
(私有)D 類 224~239 -(無分類) - 組播通信 224.0.0.1
(所有主機)E 類 240~255 - - 科研保留 無公開示例 2. 特殊 IPv4 地址(需重點記憶)
- 回環地址(Loopback Address):
127.0.0.1
~127.255.255.254
,用于設備 “自身測試”(如瀏覽器訪問?127.0.0.1
?可測試本地服務器是否正常),數據不會發送到外部網絡。- 私有地址(Private Address):僅用于內網通信,無法直接訪問互聯網(需通過路由器的 NAT 技術轉換為公網 IP),避免公網地址浪費。常見私有地址段:
- A 類:
10.0.0.0
~10.255.255.255
- B 類:
172.16.0.0
~172.31.255.255
- C 類:
192.168.0.0
~192.168.255.255
(家庭路由器默認網段多為此類,如?192.168.1.1
)- 廣播地址(Broadcast Address):子網內 “所有設備” 的地址(如子網?
192.168.1.0/24
?的廣播地址是?192.168.1.255
),發送到該地址的數據會被子網內所有設備接收。四、IP 地址的獲取方式
設備不會天生擁有 IP 地址,需通過以下方式獲取:
- 靜態配置(Static IP):手動在設備(如服務器、打印機)上設置 IP 地址、子網掩碼、網關等參數,適合需要固定地址的場景(如網站服務器,確保用戶能穩定訪問)。
- 動態配置(Dynamic IP):通過DHCP 協議(動態主機配置協議)?自動獲取地址,由路由器或 DHCP 服務器分配臨時 IP(租期通常幾小時到幾天),到期后可重新分配。家庭手機、電腦等設備默認使用此方式,無需手動設置。
五、公網 IP 與內網 IP 的區別
這是實際使用中最易混淆的概念,核心差異在于 “是否能被互聯網直接訪問”:
- 公網 IP:由運營商(如聯通、電信)分配的 “全球唯一地址”,可直接被互聯網上的其他設備訪問(如網站服務器的 IP?
202.108.22.5
,任何人都能通過該地址訪問百度)。- 內網 IP:僅用于局域網(如家庭 WiFi、公司內網)的私有地址(如?
192.168.1.100
),無法被互聯網直接訪問。內網設備要訪問互聯網,需通過路由器的NAT 轉換(將內網 IP 轉換為公網 IP),類似 “小區所有住戶共用一個大門牌號”。
總結:
3. socket套接字
在網絡編程中,socket()
?函數是創建套接字(Socket)的核心接口,用于初始化一個網絡通信端點.
1. socket () 函數的核心作用
socket()
?函數用于創建一個套接字對象,該對象是后續網絡通信(如連接、發送、接收數據)的基礎。調用后會返回一個套接字描述符(或對象引用),后續操作都通過這個描述符進行。2. socket()函數的四個參數
import socket
# socket.socket 一共四個參數:
# 第一個參數:地址族,AF_INET表示使用IPv4協議,AF_INET6表示使用IPv6協議
# 第二個參數:套接字類型,SOCK_STREAM表示流式套接字,SOCK_DGRAM表示數據報式套接字
# 第三個參數:協議,一般不用設置,默認為0。也可以指定
# 第四個參數:本地地址,一般不用設置,默認為None。
# 第一個參數
# AF_UNIX(Adress Family,即地址族 unix)
# AF_INET(Adress Family,即地址族 internet)
# AF_INET6 用于 IPv6 地址(未來也許會用到)
# AF_BLUETOOTH 用于藍牙地址
# AF_CAN 用于 CAN 總線地址
# 第二個參數
# SOCK_STREAM(Socket Type,即套接字類型,流式套接字)
# SOCK_DGRAM(Socket Type,即套接字類型,數據報式套接字)
# 第三個參數(2種示例)
# TCP(Transmission Control Protocol,即傳輸控制協議)
# SOCK_STREAM(Socket Type,即套接字類型,流式套接字)
# 協議:TCP
_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM,socket.IPPROTO_TCP)
# UDP(User Datagram Protocol,即用戶數據報協議)
# SOCK_DGRAM(Socket Type,即套接字類型,數據報式套接字)
# 協議:UDP
_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,socket.IPPROTO_UDP)
4. TCP通信
1.TCP單向通信(一個發一個收)
1.TCP服務器代碼
import socketif __name__ =='__main__':server_socket =socket.socket(socket.AF_INET,socket.SOCK_STREAM)host ='127.0.0.1'port =8888server_socket.bind((host,port))server_socket.listen(5)client_socket,arrr =server_socket.accept()while True:data = client_socket.recv(1024).decode('utf-8')print(f"Receive from client: {data}")if data =="exit":message =="exit"client_socket.send(message.encode('utf-8'))breakelif data =="?":message ="你在?什么"client_socket.send(message.encode('utf-8'))else:client_socket.send('0'.encode('utf-8'))client_socket.close()server_socket.close()print("Server has stopped")
2. TCP客戶端代碼
import socketif __name__ =='__main__':client_socket =socket.socket(socket.AF_INET,socket.SOCK_STREAM)host ="127.0.0.1"port =8888client_socket.connect((host,port))while True:message =input("請輸入:")client_socket.sendall(message.encode('utf-8'))mag =client_socket.recv(1024)if mag != b'0':print('對方發送的信息:',mag.decode('utf-8'))if message=="exit":breakclient_socket.close()
代碼解析:
我們這里需要開兩個不同的終端,保證兩個終端能夠建立起鏈接,這里兩個終端各自有自己的任務
- 服務器:啟動后監聽本地 8888 端口,等待客戶端連接。連接建立后,接收客戶端發送的消息,并根據消息內容做出響應:
- 收到 "exit" 時,斷開連接并停止服務
- 收到 "?" 時,回復 "你在?什么"
- 收到其他消息時,回復 "0"
- 客戶端:連接到服務器后,可循環輸入消息發送給服務器,同時接收服務器的響應,輸入 "exit" 時斷開連接
2.TCP雙向通信(可以互相發送和接收)
注意:如果要實現雙向通信是需要用到多線程的
1.TCP服務端代碼
'''
1, 并發通信,實現多個客戶端連接服務器
2, 實現全雙工通信,服務端與客戶端可以同時接收發數據
'''
import os
import signal
import socket
import threadingdef handle_signal(signum, frame):print('received signal {}'.format(signum))exit(0)#接收線程
def recv_data(socket):while True:recv_buffer = socket.recv(1024).decode('utf-8')if not recv_buffer:print('client is quit!')print(f'recv data from client: {recv_buffer}')if recv_buffer == 'exit':print('received exit from client')break#發送線程
def send_data(socket):while True:message = input('please input your message:')socket.send(message.encode('utf-8'))if message == 'exit':os.kill(os.getpid(), signal.SIGTERM)if __name__ == '__main__':#1, 創建socketserver_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#2, 綁定端口host = socket.gethostname()port = 5002server_socket.bind((host, port))#3, 監聽server_socket.listen(5)print('server is starting....., waiting for a connection')#4, 接收客戶端連接client_socket, addr = server_socket.accept()print('Got connection from', addr)#4, 創建2個線程實現與客戶端通信recv_thread = threading.Thread(target=recv_data,args=(client_socket,))send_thread = threading.Thread(target=send_data,args=(client_socket,))recv_thread.start()send_thread.start()# 4, 注冊一個信號signal.signal(signal.SIGTERM, handle_signal)#5, 等待線程結束recv_thread.join()send_thread.join()#6, 關閉套接字server_socket.close()client_socket.close()
2.TCP客戶端代碼
'''
客戶端
'''
import os
import socket
import threading
import signal#1, 接收線程
def recv_data(socket):while True:recv_buffer = socket.recv(1024).decode('utf-8')if not recv_buffer:print('server is quit!')breakprint(f'recv data from server {recv_buffer}')if recv_buffer == 'exit':print('received exit from server')# 終止進程os.kill(os.getpid(), signal.SIGTERM)#2, 發送線程
def send_data(socket):global recv_thread_flagwhile True:send_buffer = input('please input your data: ')socket.send(send_buffer.encode('utf-8'))if send_buffer == 'exit':#終止進程os.kill(os.getpid(), signal.SIGTERM)def handle_signal(signum, frame):print('received signal {}'.format(signum))exit(0)if __name__ == '__main__':#1, 創建socketclient_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#2, 建立連接host = '127.0.0.1'port = 5002client_socket.connect((host, port))#3, 創建2個線程實現與server端通信recv_thread = threading.Thread(target=recv_data,args=(client_socket,))send_thread = threading.Thread(target=send_data,args=(client_socket,))#4, 注冊一個信號signal.signal(signal.SIGTERM,handle_signal)#4, 等待線程結束recv_thread.start()send_thread.start()#5, 關閉socketrecv_thread.join()send_thread.join()#6, 關閉套接字client_socket.close()
代碼解析:
我們這里需要開兩個不同的終端,保證兩個終端能夠建立起鏈接,這里兩個終端各自有自己的任務,與上面相比就是多了線程的部分,然后要實現不同設備之間的通信也是如此,還需要修改IP地址即可建立連接,如果使用公網的情況下,可能會造成無法連接的情況,這個時候我們可以讓兩個設備鏈接到同一個手機熱點上,再綁定IP地址.
- 客戶端:通過兩個線程分別處理接收和發送數據,實現同時收發(全雙工),支持輸入消息發送給服務器,也能實時接收服務器消息,輸入 "exit" 可退出。
- 服務器:能監聽并接受多個客戶端連接(通過循環接受連接實現),對每個連接也用兩個線程處理收發數據,實現與客戶端的全雙工通信。
總結:如果是單方面傳送數據的話只需要socket一個就行,一個負責發送,一個負責接收,但是在這個建立連接的過程,需要經過三次握手建立連接,否則我們不能知道是否已經連接上了,然后如果是雙向傳輸接收數據的話,就需要多加一個多線程thread,在每個里面加入一個發送線程一個接收線程