二、解决黏包问题

2.1 解决黏包方法1

  • 计算消息实体的大小
  • 服务端接受两次,一次时消息大小,二次是消息实体,解决消息实体黏包
  • 客户端发送两次,一次是消息大小,一次是消息实体
  • 在两次收发之间加入一次多余通信,以防止消息大小和消息实体黏包

server端

import  socket

sk = socket.socket()

sk.bind(('127.0.0.1',9000))
sk.listen() conn,addr = sk.accept()
print(conn,addr)
while True:
cmd = input('请输入你的命令: ')
if cmd == 'q':
break conn.send(cmd.encode('gbk'))
data_length = conn.recv(1024).decode('gbk')
conn.send(b'ok') # 接受到消息大小后马上send,这样可以隔开两次recv,并且第二次接受指定长度的消息
data = conn.recv(int(data_length)).decode('gbk')
print(data) conn.close()
sk.close()

client

import  socket
import subprocess
sk = socket.socket() sk.connect(('127.0.0.1',9000)) while True:
cmd = sk.recv(1024).decode('gbk')
ret = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
std_out = ret.stdout.read()
std_err = ret.stderr.read() data_length = str(len(std_out)+len(std_err)).encode('gbk')
sk.send(data_length)
sk.recv(1024) # send消息大小后马上转入recv,隔开两次send。
sk.send(std_out)
sk.send(std_err) sk.close()

2.2  借助于struct模块

server端

import socket
import struct sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen() conn,addr = sk.accept() while True:
cmd = input('请输入命令: ')
conn.send(cmd.encode('utf-8'))
data_length_struct = conn.recv(4)
data_length = struct.unpack('i',data_length_struct)[0]
res = conn.recv(data_length).decode('gbk')
print(res) conn.close()
sk.close()

client端

import  socket
import subprocess
import struct sk = socket.socket()
sk.connect(('127.0.0.1',8080)) while True:
cmd = sk.recv(1024).decode('utf-8')
res = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout = res.stdout.read()
std_err = res.stderr.read()
data_length = len(stdout) + len(std_err)
data_length_struct = struct.pack('i',data_length)
sk.send(data_length_struct)
sk.send(stdout)
sk.send(std_err) sk.close()

2.3 通过struct定制报头传输大文件

server端

import socket
import struct
import json sk = socket.socket()
sk.bind(('127.0.0.1',8090))
sk.listen()
buffer = 2048 conn,addr = sk.accept() # 先接受报头
# 根据报头接受消息实体 struct_length = conn.recv(4) # 接受struct长度的包
bytes_head_length = struct.unpack('i',struct_length)[0] # 计算报头的长度
bytes_head = conn.recv(bytes_head_length) # 接受报头
json_head = bytes_head.decode('utf-8') # 将报头转换为str
head = json.loads(json_head) # 将报头转换为字典
fileSize = head['fileSize'] with open(head['fileName'],'wb') as f:
while fileSize:
if fileSize >= buffer:
content = conn.recv(buffer)
f.write(content)
fileSize -= buffer
else:
content = conn.recv(fileSize)
f.write(content)
break conn.close()
sk.close()

client端

import  socket
import os
import json
import struct sk = socket.socket()
sk.connect(('127.0.0.1',8090))
buffer = 2048
# 定制报头
# 先发送报头大小
# 发送报头
# 发送消息实体
head = {'fileSize':None,
'fileName':r'a.tar.gz',
'filePath':r'C:\Users\王诚\Desktop'}
file = os.path.join(head['filePath'],head['fileName'])
fileSize = os.path.getsize(file)
head['fileSize'] = fileSize
json_head = json.dumps(head) # 字典转换成了字符串
bytes_head = json_head.encode('utf-8') # 将字符串的head转换为bytes类型
bytes_head_length = len(bytes_head) # 计算bytes类型的head的大小 struct_length = struct.pack('i',bytes_head_length) # 通过struct转换为固定长度的bytes
sk.send(struct_length) # 先发报头的长度
sk.send(bytes_head) # 发报头
with open(file,'rb') as f:
while fileSize:
if fileSize >= buffer:
content= f.read(buffer)
sk.send(content)
fileSize -= buffer
else:
content = f.read(fileSize)
sk.send(content)
break sk.close()

三、检查客户端的合法性

使用hmac

server端

import  socket
import os
import hmac secret_key = b'wangys' sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen() def check_conn(conn):
msg = os.urandom(32)
conn.send(msg)
h = hmac.new(secret_key,msg)
server_msg = h.digest()
client_msg = conn.recv(1024)
res = hmac.compare_digest(server_msg,client_msg)
return res conn,addr = sk.accept()
res = check_conn(conn)
if res:
print('合法的客户端')
conn.close()
else:
print('不合法的客户端')
conn.close() sk.close()

client端

import socket
import hmac
secret_key = b'wangys' sk = socket.socket()
sk.connect(('127.0.0.1',8080)) msg = sk.recv(1024)
h = hmac.new(secret_key,msg)
client_msg = h.digest()
sk.send(client_msg) sk.close()

Python网络编程之黏包问题的更多相关文章

  1. Python学习笔记【第十四篇】:Python网络编程二黏包问题、socketserver、验证合法性

    TCP/IP网络通讯粘包问题 案例:模拟执行shell命令,服务器返回相应的类容.发送指令的客户端容错率暂无考虑,按照正确的指令发送即可. 服务端代码 # -*- coding: utf- -*- # ...

  2. 《Python》网络编程之黏包

    黏包 一.黏包现象 同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包. server端 import socket sk = s ...

  3. python socket编程和黏包问题

    一.基于TCP的socket tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端,有顺序,不重复,可靠.不会被加上数据边界. server端 import socket sk = so ...

  4. 网络编程- 解决黏包现象方案二之struct模块(七)

    上面利用struct模块与方案一比较,减少一次发送和接收请求,因为方案一无法知道client端发送内容的长度到底有多长需要和接收OK.多一次请求防止黏包,减少网络延迟

  5. Python网络编程,粘包、分包问题的解决

    tcp编程中的粘包.分包问题的解决: 参考:https://blog.csdn.net/yannanxiu/article/details/52096465 服务端: #!/bin/env pytho ...

  6. python网络编程-socket“粘包”(小数据发送问题)

    一:什么是粘包 “粘包”, 即服务器端你调用时send 2次,但你send调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的socket发送缓冲区里,等缓冲区满了.或者数据等待超时了,数据才会 ...

  7. python网络编程之粘包

    一.什么是粘包 须知:只有TCP有粘包现象,UDP永远不会粘包 粘包不一定会发生 如果发生了:1.可能是在客户端已经粘了 2.客户端没有粘,可能是在服务端粘了 首先需要掌握一个socket收发消息的原 ...

  8. Python网络编程与并发编程

    网络编程基础 黏包 , 并发 计算机网络的发展及基础网络概念 Python 中的进程与 锁 Python IO 多路复用 \协程

  9. Python之路 - 网络编程之粘包

    Python之路 - 网络编程之粘包 粘包

随机推荐

  1. 「NOIp2018」 游记

    作为一个蒟蒻要去考tg了,心理还是有点慌的.初赛70,心惊胆战很长时间,后来降分到68了,居然卡线了(震惊……) $Day \ 0$ 今天请假在家复习了,打了几个数据结构模板.希望明天考场能++rp啊 ...

  2. VUE项目中使用mint-ui框架总结

    针对PC端,element-ui可谓是首选了,UI体验效果很好. element-ui 框架官网:http://element.eleme.io/#/zh-CN/component/installat ...

  3. CF802C Heidi and Library (hard)

    题目描述 你有一个容量为k的空书架,现在共有n个请求,每个请求给定一本书ai,如果你的书架里没有这本书,你就必须以ci的价格购买这本书放入书架.当然,你可以在任何时候丢掉书架里的某本书.请求出完成这n ...

  4. DBCP 连接池

    DBCP数据源 DBCP 是 Apache 软件基金组织下的开源连接池实现 导入maven包: <!-- dbcp连接池 --> <dependency> <groupI ...

  5. 【CF1157F】Maximum Balanced Circle

    题目大意:给定一个长度为 N 的序列,求是否能够从序列中选出一个集合,使得这个集合按照特定的顺序排成一个环后,环上相邻的点之间的权值差的绝对值不超过 1. 题解:集合问题与序列顺序无关,因此可以先将序 ...

  6. django 1.开发接口环境搭建

    首先需要的环境: pycharm Python 3.6.0 django 2.1.3        安装命令: pip3 install django   查看版本号和安装的路径: pip show ...

  7. DirectX11--实现一个3D魔方(1)

    前言 可以说,魔方跟我的人生也有一定的联系. 在高中的学校接触到了魔方社,那时候的我虽然也能够还原魔方,可看到大神们总是可以非常快地还原,为此我也走上了学习高级公式CFOP的坑.当初学习的网站是在魔方 ...

  8. ArcGis Python脚本——将细碎小面合并到相邻的面积最大的面

    参数: polygon_fc 面要素类 area_limit 给定面积值,小于它的面会被合并 给定两个参数即可,这回没有注释. #polygon_fc 面要素类 #area_limit 给定面积值,小 ...

  9. JS 条形码插件--JsBarcode 在小程序中使用

    在小程序中的使用: utils文件夹下 barcode.js 粘粘以下代码 var CHAR_TILDE = 126 var CODE_FNC1 = 102 var SET_STARTA = 103 ...

  10. 利用JS写一个计算平方的网页

    <!-- 计算一个数的平方并显示出来 --> <!DOCTYPE html> <html> <head> <meta charset=" ...