套接字介紹
1.套接字 : 實現網絡編程進行數據傳輸的一種技術手段
2.Python實現套接字編程:import socket
3.套接字分類
- 流式套接字(SOCK_STREAM): 以字節流方式傳輸數據,實現tcp網絡傳輸方案。(面向連接--tcp協議--可靠的--流式套接字)
- 數據報套接字(SOCK_DGRAM):以數據報形式傳輸數據,實現udp網絡傳輸方案。(無連接--udp協議--不可靠--數據報套接字)
tcp套接字
服務端流程
1.創建套接字
sockfd=socket.socket(socket_family=AF_INET,socket_type=SOCK_STREAM,proto=0)
- 功能:創建套接字
- 參數: socket_family 網絡地址類型 AF_INET表示ipv4
- socket_type 套接字類型 SOCK_STREAM(流式) SOCK_DGRAM(數據報)
- proto 通常為0 選擇子協議
- 返回值: 套接字對象
2.綁定地址
本地地址 : 'localhost' , '127.0.0.1'
網絡地址 : '172.40.91.185'
自動獲取地址: '0.0.0.0'
sockfd.bind(addr)
- 功能: 綁定本機網絡地址
- 參數: 二元元組 (ip,port) ('0.0.0.0',8888)
3.設置監聽
sockfd.listen(n)
- 功能 : 將套接字設置為監聽套接字,確定監聽隊列大小
- 參數 : 監聽隊列大小
4.等待處理客戶端連接請求
connfd,addr = sockfd.accept()
- 功能: 阻塞等待處理客戶端請求
- 返回值: connfd 客戶端連接套接字
- addr 連接的客戶端地址
5.消息收發
data = connfd.recv(buffersize)
- 功能 : 接受客戶端消息
- 參數 :每次最多接收消息的大小
- 返回值: 接收到的內容
n = connfd.send(data)
- 功能 : 發送消息
- 參數 :要發送的內容 bytes格式
- 返回值: 發送的字節數
6.關閉套接字
sockfd.close()
- 功能:關閉套接字

客戶端流程
1.創建套接字
注意:只有相同類型的套接字才能進行通信
2.請求連接
sockfd.connect(server_addr)
- 功能:連接服務器
- 參數:元組 服務器地址
3.收發消息
注意: 防止兩端都阻塞,recv send要配合
4.關閉套接字

1 """ 2 重點代碼 3 """ 4 5 from socket import * 6 7 # 創建tcp套接字 8 sockfd = socket() # 參數默認即tcp套接字 9 10 # 連接服務端程序 11 server_addr = ("172.40.91.150",8888) # 服務端地址 12 sockfd.connect(server_addr) 13 14 while True: 15 # 消息發送接收 16 data = input("Msg>>") 17 # 如果直接回車,則跳出循環 18 if not data: 19 break 20 sockfd.send(data.encode()) # 轉換字節串發送 21 data = sockfd.recv(1024) 22 print("Server:",data.decode()) 23 24 sockfd.close()
tcp 套接字數據傳輸特點
- tcp連接中當一端退出,另一端如果阻塞在recv,此時recv會立即返回一個空字串。
- tcp連接中如果一端已經不存在,仍然試圖通過send發送則會產生BrokenPipeError
- 一個監聽套接字可以同時連接多個客戶端,也能夠重復被連接
網絡收發緩沖區
- 網絡緩沖區有效的協調了消息的收發速度
- send和recv實際是向緩沖區發送接收消息,當緩沖區不為空recv就不會阻塞。
tcp粘包
代碼示例:day2/stick_send.py,stick_recv.py
原因:tcp以字節流方式傳輸,沒有消息邊界。多次發送的消息被一次接收,此時就會形成粘包。
影響:如果每次發送內容是一個獨立的含義,需要接收端獨立解析此時粘包會有影響。
處理方法:
- 人為的添加消息邊界
- 控制發送速度

1 from socket import * 2 3 4 sockfd = socket() 5 6 server_addr = ("172.40.91.150",8888) 7 sockfd.connect(server_addr) 8 9 while True: 10 sockfd.send(b'hello') 11 12 sockfd.close()

1 import socket 2 3 sockfd = socket.socket(socket.AF_INET, 4 socket.SOCK_STREAM) 5 sockfd.bind(('0.0.0.0', 8888)) 6 7 sockfd.listen(3) 8 9 while True: 10 print("Waiting for connect ...") 11 connfd, addr = sockfd.accept() 12 print("Connect from", addr) 13 14 n = 0 15 while n < 10: 16 n += 1 17 data = connfd.recv(5) 18 print(data) 19 20 connfd.close() # 斷開連接 21 22 # 關閉套接字 23 sockfd.close()
練習:將一個文件從客戶端發送到服務端,要求文件類型隨意.
思路:讀取文件--> send發送 recv接收--> write寫入

1 from socket import * 2 import time 3 # 讀取文件--> send發送 4 s = socket() 5 s.connect(('127.0.0.1',8888)) 6 7 f = open('img.jpg','rb') 8 9 # 讀取內容,將其發送 10 while True: 11 data = f.read(1024) 12 if not data: 13 time.sleep(0.1) 14 s.send(b'##') 15 break 16 s.send(data) 17 18 time.sleep(0.1) 19 s.send("發送完畢".encode()) 20 21 f.close() 22 s.close() 23 --------------------------------------------- 24 from socket import * 25 26 s = socket() 27 s.bind(('0.0.0.0',8888)) 28 s.listen(3) 29 30 c,addr = s.accept() 31 print("Connect from",addr) 32 33 # 以二進制寫入 34 f = open('mm.jpg','wb') 35 36 #循環接收內容,寫入文件 37 while True: 38 # recv接收--> write寫入 39 data = c.recv(1024) 40 if data == b'##': 41 break 42 f.write(data) 43 44 data = c.recv(1024) 45 print(data.decode()) 46 47 f.close() 48 c.close() 49 s.close()