python socket通信 网络故障_python ,socket通信 解决粘包问题

一,昨日作业,讲解(客户端通过命令,操作服务端系统)

服务端:

# 服务端应该满足两个特点:

# 1、一直对外提供服务

# 2、并发地服务多个客户端

import subprocess

from socket import *

server = socket(AF_INET, SOCK_STREAM) # 创建对象

server.bind(('127.0.0.1', 8080)) # 监听接口

server.listen(5) # 半连接池

while True:

conn, client_addr = server.accept() # 与客户端建立双向通道

while True:

try:

cmd = conn.recv(1024) # 读去客户端发来的命令 最大是1024

if len(cmd) == 0: break # 如果 命令长度是0 则终止循环,关闭通道

obj = subprocess.Popen(cmd.decode('utf-8'), # subprocess 这个模块需要仔细研究 目前先用

shell=True,

stdout=subprocess.PIPE, # stdout是一个管道

stderr=subprocess.PIPE # stderr是一个管道

)

stdout_res = obj.stdout.read() # 得到stdout管道内容 正确内容

stderr_res = obj.stderr.read() # 得到stderr管道内容 错误内容

# print(len(stdout_res) + len(stderr_res))

conn.send(stdout_res) # 给客户端发送 命令执行正确结果 倘若是没有数据命令结果,我也不知道会怎样

conn.send(stderr_res) # 给客户端发送 命令执行错误结果

except Exception:

break

conn.close()

客户端:

from socket import *

client = socket(AF_INET, SOCK_STREAM) # 创建客户对象

client.connect(('127.0.0.1', 8080)) # 选择连接服务器地址

while True:

cmd = input('请输入命令>>:').strip() # 输入命令 此命令会被操作系统系统执行

if len(cmd) == 0: continue # 输入命令为空则返回

client.send(cmd.encode('utf-8')) # 发送命令以utf-8 事先知道服务端的解码方式

cmd_res = client.recv(1024) # 接收命令执行的结果 大小为1024

print(cmd_res.decode('GBK')) # window系统 是以GBK解码的

client.close() # 关闭管道

二,解决粘包问题:

服务端:

# 服务端应该满足两个特点:

# 1、一直对外提供服务

# 2、并发地服务多个客户端

import subprocess

import struct

from socket import *

server = socket(AF_INET, SOCK_STREAM)

server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 就是它,在bind前加

server.bind(('127.0.0.1', 8083))

server.listen(5)

# 服务端应该做两件事

# 第一件事:循环地从板连接池中取出链接请求与其建立双向链接,拿到链接对象

while True:

conn, client_addr = server.accept()

# 第二件事:拿到链接对象,与其进行通信循环

while True:

try:

cmd = conn.recv(1024)

if len(cmd) == 0: break

obj = subprocess.Popen(cmd.decode('utf-8'),

shell=True,

stdout=subprocess.PIPE,

stderr=subprocess.PIPE

)

stdout_res = obj.stdout.read()

stderr_res = obj.stderr.read()

total_size = len(stdout_res) + len(stderr_res)

# 1、先发头信息(固定长度的bytes):对数据描述信息

# int->固定长度的bytes

header = struct.pack('i', total_size)

conn.send(header)

# 2、再发真实的数据

conn.send(stdout_res)

conn.send(stderr_res)

except Exception:

break

conn.close()

客户端:

import struct

from socket import *

client = socket(AF_INET, SOCK_STREAM)

client.connect(('127.0.0.1', 8083))

while True:

cmd = input('请输入命令>>:').strip()

if len(cmd) == 0: continue

client.send(cmd.encode('utf-8'))

# 解决粘包问题思路:

# 一、先收固定长度的头:解析出数据的描述信息,包括数据的总大小total_size

header = client.recv(4)

total_size = struct.unpack('i', header)[0]

# 二、根据解析出的描述信息,接收真实的数据

# 2、recv_size=0,循环接收,每接收一次,recv_size+=接收的长度

# 3、直到recv_size=total_size,结束循环

recv_size = 0

while recv_size < total_size:

recv_data = client.recv(1024)

recv_size += len(recv_data)

print(recv_data.decode('utf-8'), end='')

else:

print()

# 粘包问题出现的原因

# 1、tcp是流式协议,数据像水流一样粘在一起,没有任何边界区分

# 2、收数据没收干净,有残留,就会下一次结果混淆在一起

# 解决的核心法门就是:每次都收干净,不要任何残留

三 解决粘包问题的终极大招

服务端:

# 服务端应该满足两个特点:

# 1、一直对外提供服务

# 2、并发地服务多个客户端

import subprocess

import struct

import json

from socket import *

server = socket(AF_INET, SOCK_STREAM)

server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 就是它,在bind前加

server.bind(('127.0.0.1', 8083))

server.listen(5)

# 服务端应该做两件事

# 第一件事:循环地从板连接池中取出链接请求与其建立双向链接,拿到链接对象

while True:

conn, client_addr = server.accept()

# 第二件事:拿到链接对象,与其进行通信循环

while True:

try:

cmd = conn.recv(1024)

if len(cmd) == 0: break

obj = subprocess.Popen(cmd.decode('utf-8'),

shell=True,

stdout=subprocess.PIPE,

stderr=subprocess.PIPE

)

stdout_res = obj.stdout.read()

stderr_res = obj.stderr.read()

total_size = len(stdout_res) + len(stderr_res)

# 1、制作头

header_dic = {

"filename": "a.txt",

"total_size": total_size,

"md5": "123123xi12ix12"

}

json_str = json.dumps(header_dic)

json_str_bytes = json_str.encode('utf-8')

# 2、先把头的长度发过去

x = struct.pack('i', len(json_str_bytes)) # i 模式把int类型的模式转换成 固定的4个字节的Bytes

conn.send(x)

# 3、发头信息

conn.send(json_str_bytes) # 这个Bytes会和一下的Bytes粘到一起

# 4、再发真实的数据

conn.send(stdout_res)

conn.send(stderr_res)

except Exception:

break

conn.close()

客户端:

import struct

import json

from socket import *

client=socket(AF_INET,SOCK_STREAM)

client.connect(('127.0.0.1',8083))

while True:

cmd=input('请输入命令>>:').strip()

if len(cmd) == 0:continue

client.send(cmd.encode('utf-8'))

# 接收端

# 1、先手4个字节,从中提取接下来要收的头的长度

x=client.recv(4)

header_len=struct.unpack('i',x)[0] # 解包操作,把你收到的东西解成一个小元组

# 2、接收头,并解析

json_str_bytes=client.recv(header_len)

json_str=json_str_bytes.decode('utf-8')

header_dic=json.loads(json_str)

print(header_dic)

total_size=header_dic["total_size"]

# 3、接收真实的数据

recv_size = 0

while recv_size < total_size:

recv_data=client.recv(1024)

recv_size+=len(recv_data)

print(recv_data.decode('utf-8'),end='')

else:

print()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值