python之socket编程3
1 什么是粘包
只有TCP有粘包现象,UDP永远不会粘包
应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向连接的,面向流的,收发两端都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法,将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这也是容易出现粘包问题的原因;
而UDP面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据。
粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。
两种情况下会发生粘包
(1.)发送端需要等缓冲区满才发送出去,造成粘包。发送数据时间间隔很短,数据很小会合到一起,产生粘包
(2)接收方不及时收取缓冲区的包,造成多个包接收,客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包
#服务端
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=("127.0.0.1",8080)
phone.bind(ip_port)
phone.listen(5)
conn,addr=phone.accept()
data1=conn.recv(1024)
data2=conn.recv(1024)
print("第1个包",data1)
print("第2个包",data2) #客户端
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=("127.0.0.1",8080)
phone.connect(ip_port)
phone.send("helloworld".encode("utf8"))
phone.send("SB".encode("utf8")) >>
第1个包 b'helloworldSB'#产生粘包现象
第2个包 b''
使用时间模块,并不能够彻底解决问题
#服务端
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=("127.0.0.1",)
phone.bind(ip_port)
phone.listen()
conn,addr=phone.accept()
data1=conn.recv()
data2=conn.recv()
print("第1个包",data1)
print("第2个包",data2) #客户端
import socket,time
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=("127.0.0.1",)
phone.connect(ip_port)
phone.send("helloworld".encode("utf8"))
time.sleep()
phone.send("SB".encode("utf8")) >>
第1个包 b'helloworld'#send先执行一次后,发送至客户端内存
第2个包 b'SB'#延迟三秒后,,再执行发送
#服务端
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=("127.0.0.1",8080)
phone.bind(ip_port)
phone.listen(5)
conn,addr=phone.accept()
data1=conn.recv(1)
data2=conn.recv(1024)
print("第1个包",data1)
print("第2个包",data2) #客户端
import socket,time
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=("127.0.0.1",8080)
phone.connect(ip_port) phone.send("helloworld".encode("utf8"))
time.sleep(3)
phone.send("SB".encode("utf8"))
>>
第1个包 b'h' #recv第一次只取一个字节
第2个包 b'elloworld' #第二次再次执行 ,”SB”还在服务器的内存中
2 自定制报头解决粘包问题
数据封装报头:
固定长度
包含对将要发送数据的描述信息
struct模块
import struct
print(struct.pack("i",111))
>>
b'o\x00\x00\x00' #转成字节模式 import struct
res=struct.pack("i",111)#struct.pack 打包
print(len(res))
>>
4 #转成字节长度为固定4 import struct
res=struct.pack("i",111)
# print(len(res))
print(struct.unpack("i",res))#解包
(111,)#获得以元组形式的结果
简单实现:
#服务端
import socket
import struct
import subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=("127.168.0.1",8080)
phone.bind(ip_port)
phone.listen(5)
#连接循环
while True:
conn,addr=phone.accept()
print("cline addr",addr)
#通讯循环
while True:
try:
cmd=conn.recv(1024)
res=subprocess.Popen(cmd.decode("utf8"),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out_res=res.stdout.read()
err_res=res.stderr.read()
data_size=len(out_res)+len(err_res)
#发送报头
conn.send(struct.pack("i",data_size))
#发送数据部分
conn.send(out_res)
conn.send(err_res)
except Exception:
break
conn.close()
phone.close() #客户端
import socket
import struct
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=("127.168.0.1",8080)
phone.connect(ip_port)
#通信循环
while True:
#发消息
cmd=input(">>").strip()
if not cmd:continue
phone.send(bytes(cmd,encoding="utf8"))
#收报头
baotou=phone.recv(4)
data_size=struct.unpack("i",baotou)[0]
#收数据
recv_size=0
recv_data=b""
while recv_size<data_size:
data=phone.recv(1024)
recv_size+=len(data)
recv_data+=data
print(recv_data.decode("gbk"))
phone.close()
完全解决:
#服务端
import socket
import struct
import subprocess
import json
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=("127.168.0.1",8080)
phone.bind(ip_port)
phone.listen(5)
#连接循环
while True:
conn,addr=phone.accept()
print("cline addr",addr)
#通讯循环
while True:
try:
cmd=conn.recv(1024)
res=subprocess.Popen(cmd.decode("utf8"),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out_res=res.stdout.read()
err_res=res.stderr.read()
data_size=len(out_res)+len(err_res)
head_dic={"data_size":data_size}
head_json=json.dumps(head_dic)
head_bytes=head_json.encode("utf8")
#发送报头
head_len=len(head_bytes)
conn.send(struct.pack("i",data_size))
conn.send(head_bytes)
#发送数据部分
conn.send(out_res)
conn.send(err_res)
except Exception:
break
conn.close()
phone.close() #客户端
import socket
import struct
import json
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=("127.168.0.1",8080)
phone.connect(ip_port)
#通信循环
while True:
#发消息
cmd=input(">>").strip()
if not cmd:continue
phone.send(bytes(cmd,encoding="utf8"))
#收报头的长度
head_struct=phone.recv(4)
head_len=struct.unpack("i",head_len)[0] #再收报头
head_bytes=phone.recv(head_len)
head_json=head_bytes.decode("utf8")
head_dic=json.loads(head_json)
print(head_dic)
data_size=head_dic["data_size"] #收数据
recv_size=0
recv_data=b""
while recv_size<data_size:
data=phone.recv(1024)
recv_size+=len(data)
recv_data+=data
print(recv_data.decode("gbk"))
phone.close()
python之socket编程3的更多相关文章
- 转:Python 的 Socket 编程教程
这是用来快速学习 Python Socket 套接字编程的指南和教程.Python 的 Socket 编程跟 C 语言很像. Python 官方关于 Socket 的函数请看 http://docs. ...
- Python 3 socket 编程
Python 3 socket编程 一 客户端/服务器架构 互联网中处处是C/S架构 1.C/S结构,即Client/Server(客户端/服务器)结构 2.在互联网中处处可见c/s架构 比如说浏览器 ...
- 最基础的Python的socket编程入门教程
最基础的Python的socket编程入门教程 本文介绍使用Python进行Socket网络编程,假设读者已经具备了基本的网络编程知识和Python的基本语法知识,本文中的代码如果没有说明则都是运行在 ...
- python之socket编程(一)
socket之前我们先来熟悉回忆几个知识点. OSI七层模型 OSI(Open System Interconnection)参考模型是国际标准化组织(ISO)制定的一个用于计算机或通信系统间互联的标 ...
- Python:socket编程教程
ocket是基于C/S架构的,也就是说进行socket网络编程,通常需要编写两个py文件,一个服务端,一个客户端. 首先,导入Python中的socket模块: import socket Pytho ...
- python学习------socket编程
一 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端为你提供视频 ...
- Python基础socket编程
Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...
- Python基础-socket编程
一.网络编程 自从互联网诞生以来,现在基本上所有的程序都是网络程序,很少有单机版的程序了. 计算机网络就是把各个计算机连接到一起,让网络中的计算机可以互相通信.网络编程就是如何在程序中实现两台计算机的 ...
- Python菜鸟之路:Python基础-Socket编程-2
在上节socket编程中,我们介绍了一些TCP/IP方面的必备知识,以及如何通过Python实现一个简单的socket服务端和客户端,并用它来解决“粘包”的问题.本章介绍网络编程中的几个概念:多线程. ...
- Python 006- python socket编程详细介绍
转自https://blog.csdn.net/rebelqsp/article/details/22109925 Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供 ...
随机推荐
- [转] AES,SHA1,DES,RSA,MD5区别
AES:更快,兼容设备,安全级别高: SHA1:公钥后处理回传 DES:本地数据,安全级别低 RSA:非对称加密,有公钥和私钥 MD5:防篡改 相关: 公开密钥加密(英语:public-key cry ...
- 标准I/O的缓冲
标准I/O实现了三种类型的用户缓冲,并为开发者提供了接口,可以控制缓冲区类型和大小. 无缓冲(Unbuffered) 不执行用户缓冲.数据直接提交给内核.因为这种无缓冲模式不支持用户缓冲(用户缓冲一般 ...
- jquery实时监听输入框值变化
在做web开发时候很多时候都需要即时监听输入框值的变化,以便作出即时动作去引导浏览者增强网站的用户体验感.而采用onchange时间又往往是在输入框失去焦点(onblur)时候触发,有时候并不能满足条 ...
- C语言之指针变量
菜单导航 1.指针变量 2.指针和数组 3.常量指针和指向常量的指针 4.指针和字符串的关系 5.数组越界造成的访问不属于自己的内存空间现象 6.引用数据类型和基本数据类型,形参和实参 7.字符串和字 ...
- JMeter执行压测输出HTML图形化报表(二)
命令行模式将jtl转成测试图表 注意此方法只使用jmeter3.0以后版本 第一种:在测试过程中将jtl转成测试报告(在jmeter的bin目录下执行) jmeter -n -t baidu_requ ...
- 042 spring boot在启动之后,自动关闭
在学校数据源的时候,还没有开始使用数据源,项目就关闭了. 为了学习数据源,就只能使用测试类. 但是,最近需要使用restful进行测试的时候,项目是关闭的,就很糟糕,不好进行测试. 1.日志如下: D ...
- 20165235实验四 Android程序设计
20165235实验四 Android程序设计 实验课程:JAVA编程设计 实验名称:Android开发 姓名:祁瑛 学号:20165235 实验时间:2018.05.16 指导老师:娄家鹏 Andr ...
- 根据cookie记录跟踪ID来确定分享对象
一 :思路分析 1:用户注册的时候标记推客 2:推客生成分享链接 分享链接构成 (环境前缀+(此链接打开时需要调用的接口+推客的标记+&url=(商品的链接))) 3:需要写一个分享链接调 ...
- API接口设计,rest,soap
REST之前的重要协议SOAP rest(简单理解风格.约束.设计理念) rest之前是SOAP:SOAP Web API采用RPC风格,它采用面向功能的架构,所以我们在设计SOAP Web API的 ...
- 002.Zabbix简介
一 Zabbix简介 1.1 概述 Zabbix是一个企业级的高度集成开源监控软件,提供分布式监控解决方案.可以用来监控设备.服务等可用性和性能. 1.2 所支持监控方式 目前由zabbix提供包括但 ...