struct模塊是如何使用的呢?
import struct msg = "我正在學習python的網絡編程。" msg_bs = msg.encode("utf-8") # 將數據編碼轉為字節 res = struct.pack("i", len(msg_bs)) # 將字節數據的長度打包成固定長度(4) print(res) bs = b"'\x00\x00\x00" res = struct.unpack("i", bs) # 解包,解包后得到一個數組,取第一個元素即可 print(res) msg_bs_len = res[0] print(msg_bs_len)
執行結果:
b"'\x00\x00\x00" (39,) 39
注意:
這里的i是int的意思,4個字節,就是4*8=32位,2**32次方就是可以打包的長度。也就是可以一次滿足4G大小數據的打包。
看一組使用struct模塊的tcp通信流程
---------------------------------------------struct_server.py------------------------------------------- # coding:utf-8 import struct import socket import subprocess server = socket.socket() ip_port = ("127.0.0.1", 8001) server.bind(ip_port) server.listen(5) conn, addr = server.accept() while 1: from_client_msg = conn.recv(1024) print("來自客戶端的消息:", from_client_msg.decode("utf-8")) if not from_client_msg.decode("utf-8"): print("stop") break res = subprocess.Popen( from_client_msg.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) cmd_result = res.stderr.read() if not cmd_result: cmd_result = res.stdout.read() cmd_result_len = len(cmd_result) print("一會要發送數據的真實長度:", cmd_result_len) conn.send(struct.pack('i', cmd_result_len)) # 先發送struct打包后的數據長度 conn.sendall(cmd_result) # 再發送真實數據 conn.close() server.close()
---------------------------------------------struct_client.py------------------------------------------- # coding:utf-8 import socket import struct client = socket.socket() ip_port = ("127.0.0.1", 8001) client.connect(ip_port) while 1: cmd = input(">>>: ").strip() if not cmd: break client.send(cmd.encode("utf-8")) # 發送dir或ipconfig命令 from_server_msg = client.recv(4) # 先接收struct打包的后數據長度 from_server_msg_len = struct.unpack('i', from_server_msg) # struct解包 from_server_msg_len = from_server_msg_len[0] # 獲取真實數據的長度 print("來自服務端的消息:", from_server_msg, from_server_msg_len) from_server_real_msg = client.recv(1024) # 再接收真實數據 real_msg_len = len(from_server_real_msg) # 獲取第一次獲取真實數據的長度 while from_server_msg_len > real_msg_len: # 如果一次沒有獲取完真實數據 from_server_real_msg += client.recv(1024) # 再次接收真實數據 real_msg_len = len(from_server_real_msg) print("來自服務端的消息:", from_server_real_msg.decode("gbk")) client.close()
總結:
1、使用struct模塊先把要發送的數據打包成固定長度(4)的字節發送出去,再發送數據。
再看一組struct模塊使用的實例
# tcp_server.py import socket import struct sk = socket.socket() # 創建socket對象 sk.bind(("127.0.0.1", 9998)) # 綁定IP和端口 sk.listen() # 開啟監聽 conn, address = sk.accept() # 等待客戶端連接 阻塞 while 1: # 讓服務端和客戶端循環通信 send_msg = input(">>>:").strip() # 要發送的消息 send_msg_bs = send_msg.encode("utf-8") # 消息編碼為字節 conn.send(struct.pack("i", len(send_msg_bs))) # 先發送消息的長度(打包成固定4個字節長度發送出去) conn.send(send_msg_bs) # 再發送消息給客戶端 if send_msg.upper() == "BYE": # 如果發送的消息是BYE就退出循環 break msg_len = struct.unpack("i", conn.recv(4))[0] # 先接收4個字節的消息長度 recv_msg = conn.recv(msg_len) # 再接收消息 print("來自客戶端的消息:", recv_msg.decode("utf-8")) if recv_msg.decode("utf-8").upper() == "BYE": # 如果來自客戶端的消息是BYE就退出循環 break conn.close() # 關閉conn連接 sk.close() # 關閉sk連接
# tcp_client.py import socket import struct sk = socket.socket() # 創建socket對象 sk.connect(("127.0.0.1", 9998)) # 連接服務端 while 1: # 服務端和客戶端循環通訊 msg_len = struct.unpack("i", sk.recv(4))[0] # 先接收消息長度 recv_msg = sk.recv(msg_len) # 再接收消息 print("來自服務端的消息:", recv_msg.decode("utf-8")) if recv_msg.decode("utf-8").upper() == "BYE": # 如果來自服務端的消息是BYE就直接退出循環 break send_msg = input(">>>:").strip() # 要發送給服務端的消息 send_msg_bs = send_msg.encode("utf-8") sk.send(struct.pack("i", len(send_msg_bs))) # 先發送消息的長度 sk.send(send_msg_bs) # 再發送消息 if send_msg.upper() == "BYE": # 如果發送的消息是BYE就直接退出循環 break sk.close() # 關閉sk連接
把發送消息和接收消息封裝到函數中
# server_tcp.py import socket import struct def my_send(sk, msg): """ 發送消息 :param msg: :return: """ msg_bs = msg.encode("utf-8") struct_len = struct.pack("i", len(msg_bs)) sk.send(struct_len) sk.send(msg_bs) def my_recv(sk): """ 接收來自消息 :param sk: :return: """ msg_len = struct.unpack("i", sk.recv(4))[0] msg_bs = sk.recv(msg_len) return msg_bs.decode("utf-8") if __name__ == '__main__': sk = socket.socket() # 創建socket對象 sk.bind(("127.0.0.1", 6666)) # 綁定IP和端口號 sk.listen() # 開啟監聽 print("開啟監聽!") conn, address = sk.accept() # 等待客戶端連接 阻塞 print("客戶端連接成功!") while 1: # 開始和客戶端聊天,以下程序是服務端先發送消息 send_msg = input(">>>:").strip() my_send(conn, send_msg) if send_msg.upper() == "BYE": break msg = my_recv(conn) print(f"來自客戶端的消息:{msg}") if msg.upper() == "BYE": break conn.close() sk.close()
# client_tcp.py import socket import struct def my_send(sk, msg): """ 發送消息 :param msg: :return: """ msg_bs = msg.encode("utf-8") struct_len = struct.pack("i", len(msg_bs)) sk.send(struct_len) sk.send(msg_bs) def my_recv(sk): """ 接收來自消息 :param sk: :return: """ msg_len = struct.unpack("i", sk.recv(4))[0] msg_bs = sk.recv(msg_len) return msg_bs.decode("utf-8") if __name__ == '__main__': sk = socket.socket() # 創建socket對象 sk.connect(("127.0.0.1", 6666)) # 連接服務端 while 1: recv_msg = my_recv(sk) print("來自服務端的消息:", recv_msg) if recv_msg.upper() == "BYE": break send_msg = input(">>>:").strip() my_send(sk, send_msg) if send_msg.upper() == "BYE": break sk.close()
總結:
1、以上例子都是最簡單的一發一收的過程,並且一次發送的數據量都非常的小。
如果遇到一次發送數據比較大的時候,應該怎么辦呢?