(4)socket套接字使用模版
socket套接字使用模版
【一】客户端
# -*-coding: Utf-8 -*-
# @File : 客户端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/22
import json
from socket import *
# 解指定数据长度
import struct
# 创建 socket 对象
client = socket(AF_INET, SOCK_STREAM)
# 创建链接 IP 和 端口
client.connect(('127.0.0.1', 8085))
while True:
msg = input('enter msg :>>>').strip()
# 输入的内容不能为空
if len(msg) == 0:
continue
# 传输过程中的数据为二进制数据。对文本数据进行转码
msg = msg.encode('utf-8')
client.send(msg)
# 接收来自服务端返回的结果
# (1.1) 先收四个字节的数据,从接收到的数据中解析出json格式的二进制数据的长度
json_data_size_unpack = client.recv(4)
# 解包返回的是元祖。元祖第一个参数就是打包的数字
json_data_size = struct.unpack('i', json_data_size_unpack)[0]
# (1.2) 对 服务端 返回的数据中指定长度进行截取 拿到 json 格式的二进制数据
json_data_bytes = client.recv(json_data_size)
# (1.3) 对指定数据进行json格式的解码并取出需要的信息
header_dict_str = json_data_bytes.decode('utf-8')
header_dict = json.loads(header_dict_str)
# (1.4) 取出字典中的信息总长度
recv_total_size = header_dict['total_size']
# (2) 接收真实的数据
# recv_size = 0 ,循环接收,每接收一次,recv_size += 接收的长度
# (3) 直到 recv_size = recv_total_size 表示接受信息完毕,结束循环
# 初始化数据长度
recv_size = 0
while recv_size < recv_total_size:
# 本次接收 最多能接收 1024 字节的数据
msg_from_server = client.recv(1024)
# 本次接收到的打印的数据长度
recv_size += len(msg_from_server)
# 对服务端返回的信息进行解码(Mac/Linux解码用utf-8,Windows用GBK)
msg_from_server = msg_from_server.decode('gbk')
print(msg_from_server, end='')
else:
print('命令结束')
client.close()
【二】服务端
# -*-coding: Utf-8 -*-
# @File : 服务端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/22
# client.connect(('127.0.0.1', 8880))
# 客户端设置的 ip 和 port
from socket import *
# 执行命令模块
import subprocess
# 将数据打包成指定4个长度的数据
import struct
# 将头部信息转成json格式(通用信息格式)
import json
# (1)创建服务对象
# 参数 : AF_INET(默认,初始化操作)
# 参数 : SOCK_STREAM(流式传输协议)
server = socket(AF_INET, SOCK_STREAM)
# (2)建立链接桥梁 --(呼应客户端的 ip 和 port)
IP = '127.0.0.1'
PORT = 8080
server.bind((IP, PORT))
# (3)指定半连接池大小
server.listen(5)
# (4)接收数据和发送数据
while True:
# (4.1)从半连接池里面取出链接请求,建立双向链接,拿到连接对象
# (4.2)返回参数解压赋值 : (建成的链接对象,客户端的 ip port)
conn, client_addr = server.accept()
while True:
# (5)检测可能会抛出的异常 并 对异常做处理
try:
# (5.1)基于 取出的链接对象 进行通信
# (5.2)接受客户端传入的指定信息
cmd_from_client = conn.recv(1024)
# 不允许传过来的信息为空
if len(cmd_from_client) == 0:
break
# (5.3)通过subprocess模块,执行客户端传过来的命令
# (5.3.1)接收执行命令的结果
msg_server = subprocess.Popen(cmd_from_client.decode('utf-8'), # 对命令进行解码
shell=True, # 执行shell命令
stdout=subprocess.PIPE, # 管道一
stderr=subprocess.PIPE, # 管道二
)
# (5.3.2)返回命令的结果 ---- 成功或失败
# ****** 对于返回给客户端的数据,客户端 Linux系统可以用utf-8解码,Windows系统需要用gbk解码 ******
true_msg = msg_server.stdout.read() # 读取到执行成功的结果 ---- 二进制数据类型
false_msg = msg_server.stderr.read() # 读取到执行失败的结果 ---- 二进制数据类型
# (5.4):头部信息(程序执行的结果,成功信息长度 + 失败信息长度)
total_size_from_server = len(true_msg) + len(false_msg)
# (5.5)自定义头部信息(存储任意数据拼接数据)
headers_dict = {
'file_name': 'a.txt',
'total_size': total_size_from_server,
'md5': 'md5'
}
# (5.6)打包头部信息 - 将字典转成 json 格式数据类型
json_data_str = json.dumps(headers_dict)
# (5.7)将 json 格式数据转成二进制数据传输
json_data_bytes = json_data_str.encode('utf-8')
# (5.8)int类型 -----> 将json格式的二进制数据打成固定长度的 bytes
# 参数 i 表示是整型,具体解释参考文档
json_data_size_pack = struct.pack('i', len(json_data_bytes))
conn.send(json_data_size_pack)
# (5.9)发送打包好的头信息
conn.send(json_data_bytes)
# (5.10)反馈信息(成功信息 + 失败信息)给 发送信息的客户端
conn.send(true_msg)
conn.send(false_msg)
except Exception as e:
break
# 关闭服务端
conn.close()
【三】struct模块参数详解
struct.pack()
是Python内置模块struct
中的一个函数,它的作用是将指定的数据按照指定的格式进行打包,并将打包后的结果转换成一个字节序列(byte string),可以用于在网络上传输或者储存于文件中。
struct.pack(fmt, v1, v2, ...)
其中,fmt
为格式字符串,指定了需要打包的数据的格式,后面的v1
,v2
,...则是需要打包的数据。这些数据会按照fmt
的格式被编码成二进制的字节串,并返回这个字节串。
fmt
的常用格式符如下:
x
--- 填充字节c
--- char类型,占1字节b
--- signed char类型,占1字节B
--- unsigned char类型,占1字节h
--- short类型,占2字节H
--- unsigned short类型,占2字节i
--- int类型,占4字节I
--- unsigned int类型,占4字节l
--- long类型,占4字节(32位机器上)或者8字节(64位机器上)L
--- unsigned long类型,占4字节(32位机器上)或者8字节(64位机器上)q
--- long long类型,占8字节Q
--- unsigned long long类型,占8字节f
--- float类型,占4字节d
--- double类型,占8字节s
--- char[]类型,占指定字节个数,需要用数字指定长度p
--- char[]类型,跟s
一样,但通常用来表示字符串?
--- bool类型,占1字节
具体的格式化规则可以在Python文档中查看(链接)。
本文来自博客园,作者:Chimengmeng,转载请注明原文链接:https://www.cnblogs.com/dream-ze/p/17499411.html