一.半连接数:
import socket
server=socket.socket()
server.bind(('127.0.0.1', 1263))
server.listen()
server.accept()
三次握手没有完成 称之为半连接
原因1 恶意客户端没有返回第三次握手信息
原因2 服务器没空及时处理你的请求
socket中 listen(半连接最大数量)
# 最大半连接数 本质就是一个数组 未完成链接的socket 就会被加入到数组中 ,
# 每一次执行accept 就会完成一个三次握手 ,如果达到最大限制 额外的客户端将直接被拒绝
# 我们可以调整内核参数来修改 最大等待时长 如果超时 客户还是没有回复第三次握手信息 就直接删除
# 二.粘包问题
TCP流式协议, 数据之间没有分界, 就像水 一杯水和一杯牛奶倒在一起了!
UDP 用户数据报协议
粘包 仅发生在TCP协议中
1. 发送端 发送的数据量小 并且间隔短 会粘
2. 接收端 一次性读取了两次数据的内容 会粘
3. 接收端 没有接收完整 剩余的内容 和下次发送的粘在一起
无论是那种情况,其根本原因在于 接收端不知道数据到底有多少
解决方案就是 提前告知接收方 数据的长度
# 解决方案
先发长度给对方 再发真实数据
#发送端
1.使用struct 将真实数据的长度转为固定的字节数据
2.发送长度数据
3.发送真实数据
import socket
import subprocess
import struct
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("127.0.0.1",1688))
server.listen()
# back
while True:
# socket,addr一个元组 客户端的ip和port
client,addr = server.accept()
print("客户端链接成功!")
# 循环收发数据
while True:
try:
cmd = smallTool.recv_data(client)
if not cmd:
break
print(cmd)
p = subprocess.Popen(cmd.decode("utf-8"),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
# 不要先读err错误信息 它会卡主 原因不详 linux不会有问题 tasklist netstat - ano啥的
data = p.stdout.read()
err_data = p.stderr.read()
len_size = len(data) + len(err_data)
print("服务器返回了: %s " % len_size)
len_bytes = struct.pack("q",len_size)
# 在发送真实数据前先发送 长度
client.send(len_bytes)
# 返回的结果刚好就是二进制
# 发送真实数据
client.send(data + err_data)
except ConnectionResetError as e:
print("客户端了挂了!",e)
break
client.close()
接收端
1.先收长度数据 字节数固定
2.再收真实数据 真实可能很长 需要循环接收
"""
客户端输入指令
服务器接收指令并执行 最后返回执行结果
"""
import socket
client = socket.socket()
try:
client.connect(("127.0.0.1",1688))
print("链接成功!")
while True:
msg = input("请输入要执行指令:").strip()
if msg == "q": break
if not msg: continue
# 发送指令
# 先发长度
len_bytes = struct.pack("q",len(msg.encode("utf-8")))
client.send(len_bytes)
# 在发指令
client.send(msg.encode("utf-8"))
data = smallTool.recv_data(client)
print(data.decode("GBK"))
client.close()
except ConnectionRefusedError as e:
print("链接服务器失败了!",e)
except ConnectionResetError as e:
print("服务器挂了!", e)
client.close()
发送端和接收端必须都处理粘包 才算真正的解决了
struct pack//unpack
python中的struct主要是用来处理C结构数据的,读入时先转换为Python的字符串类型,然后再转换为Python的结构化类型,比如元组(tuple)啥的~。一般输入的渠道来源于文件或者网络的二进制流。
# struct.pack()和struct.unpack()
# 在转化过程中,主要用到了一个格式化字符串(format strings),用来规定转化的方法和格式。
# struct.pack(fmt,v1,v2,.....)
# 将v1,v2等参数的值进行一层包装,包装的方法由fmt指定。被包装的参数必须严格符合fmt。最后返回一个包装后的字符串。
# struct.unpack(fmt,string)
# 解包。比如pack打包,然后就可以用unpack解包了。返回一个由解包数据(string)得到的一个元组(tuple), 即使仅有一个数据也会被解包成元组。
try: excapt: finally:
f = None
try:
f = open(r"今日内容s","rt")
print( f.read())
# {}["name"]
except Exception as e:
print(e)
finally: # 最终
if f:f.close()
print("文件关了!")
## 自定义报头
当需要在传输数据
发送端
1.发送报头长度
2. 发送报头数据
3. 发送文件内容
接收端
接收报头长度
接收报头信息
接收文件内容