网络编程之粘包

粘包:

传输层协议有tcp和udp两种

tcp:Transmission Control Protocol

传输控制协议,基于数据流,收发的消息不能为空,需要在客户端和服务端都添加空消息的处理机制

tcp是可靠性协议,数据的收发都需要确认信息,这就降低了传输效率,故为了减少确认次数,tcp采用了nagle算法

将多次间隔短且数据小的数据合成一个数据流,然后发送,tcp的数据没有明确的界限,无法区分数据的开始和结束,

这就导致了可能将多个信息并为一条信息,也就是粘包

还有一种粘包情况是当一个数据包过大时,操作系统的缓存只会提供一部分数据给应用程序,导致我们只读了包的一部分内容,其余内容当我们再次接收时会发送过来

综上 tcp粘包问题的产生,是因为传输数据没有具体的界限,所以解决粘包问题需要知道数据的明确长度,当长度小时我们明确接受该长度的数据,当长度过大时,我们采用循环接受的方法来取

具体操作:1.发送方获取消息的具体长度

2.发送方先将该长度发送给接收方

3.接收方通过此长度准确接收消息

上述操作使用了第三方模块struct

struct的作用,pack方法将一个整数,转换成固定长度的bytes类型

unpack方法将一个bytes类型的长度转换为整数

解决粘包问题的核心,给数据流添加自定义报头

报头可以存放发送时间,真实信息大小,通过json模块保存成字典或列表,以便我们可以更方便的取值

具体代码(以cmd实现客户端系统命令为例子):

服务端

from socket import *
import json
import struct
import subprocess
import datetime
s = socket()#创建套接字对象
s.bind(("127.0.0.1",8888))#绑定ip和端口
s.listen(5)#监听,规定半连接池大小
while True:
    conn,addr = s.accept()#接收客户端连接,三次握手
    while True:
        try:
            cmd = conn.recv(1024)#接收cmd命令
            if not cmd:#linux系统客户端强退时会不停发空消息,故此处为防止客户端突然退出,跨平台性
                conn.close()
                break
            obj  = subprocess.Popen(cmd.decode("utf-8"),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)#使用subprocess模块完成系统命令
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()
            msg = stdout +stderr

            s_dic = {}#自定义报头
            s_dic["time"] = str(datetime.datetime.now())#添加key  time
            s_dic["size"] = len(msg)#添加key size
            head_data = json.dumps(s_dic)#使用json序列化成json格式的字符串
            head_len = struct.pack("i",len(head_data))#使用struct模块获取报头长度,将整形转换为二进制,固定为4个字节大小
            conn.send(head_len)#先发送报头长,此时使用的“i”模式为4字节,故客户端以4个字节接收,接收后使用struct模块反解出报头信息长准确接收报头信息,
#防止报头信息和具体信息粘包
            conn.send(head_data.encode("utf-8"))#将json格式的字符串转换成二进制,发送报头信息,报头信息的作用,客户端可以通过报头信息获取具体信息长度
            conn.send(msg)#发送具体信息
        except ConnectionResetError:
            conn.close()
            break
客户端:
     c = socket()#创建客户端套接字对象
     c.connect(("127.0.0.1",8888))#链接服务器

 while True:
     cmd = input(">>>:").strip().encode("utf-8")#接收命令
     c.send(cmd)#发送命令给服务器
     lenth = c.recv(4)#接收报头长度
     head_lenth = struct.unpack("i",lenth)[0]#unpack出整形报头信息的长度
     head_data = c.recv(head_lenth)#准确接收报头信息
     dic = json.loads(head_data.decode("utf-8"))#获取报头信息
     print(dic)
     rev_size = 0
     all_data = b""
     while rev_size < dic["size"]:#由报头信息或得的具体信息长
         data = c.recv(1024)#循环接收
         rev_size += len(data)
         all_data += data

     print(all_data.decode("gbk"))

udp协议

user datagram protocol,用户数据报协议

没有链接,面向消息,效率高,udp数据包有报头,故不会产生粘包问题

原文地址:https://www.cnblogs.com/robert-zhou/p/10182485.html

时间: 2024-11-08 21:56:35

网络编程之粘包的相关文章

网络编程中粘包的处理方法

写在前面的话:因为自己是才解除网络编程,在工作中第一次遇到粘包问题,我还不知道它是叫粘包问题,所以被整的晕头转向,百思不得其解,自己的代码到底哪里出了问题,最后只能单步调试程序才发现接收方接收到的数据并不一定是按自己设想那样,一次接收整个数据包,当时就想到用文件长度来判断是否接收完文件,之后读了UNP才知道是粘包问题.记录以下当时自己的处理方法. 面对网络编程中的发送文件时的粘包问题,我的处理方法是在要发送文件前,首先发送文件的长度,获取的文件长度是UlongLong类型的整数,发送 时需要转换

网络编程基础粘包现象

粘包 tcp是流式传输,字节流,数据与数据之间是没有边界的 流式传输优点: 不限定长度 可靠传输 缺点: 慢 和一个人的通信连接conn会一直占用我们的通信资源 udp协议,面向数据包的传输 数据包优点 快 由于不需要建立连接,所以谁发的消息我都能接受到 缺点 不能传输过长的数据 不可靠 粘包现象 由于流式传输的特点,产生了数据连续发送的粘包现象. 在一个conn建立起来的连接上传输的多条数据是没有边界的 数据的发送和接收实际上不是在执行send/recv的时候就立刻被发送和接收,而是需要经过操

Learning-Python【29】:网络编程之粘包

粘包问题 上一篇博客遗留了一个问题,在接收的最大字节数设置为 1024 时,当接收的结果大于1024,再执行下一条命令时还是会返回上一条命令未执行完成的结果.这就是粘包问题. 因为TCP协议又叫流式协议,每次发送给客户端的数据实际上是发送到客户端所在操作系统的缓存上,客户端就是一个应用程序,需要通过操作系统才能调到缓存内的数据,而缓存的空间是一个队列,有 “先进先出” 的思想,当第一次的 tasklist 数据未接收完,第二次又来一个 dir 的数据时,只能等第一次先全部接收完成才会接收后面的.

网络编程-之------粘包现象

一.什么是粘包 须知:只有TCP有粘包现象,UDP永远不会粘包 粘包不一定会发生 如果发生了:1.可能是在客户端已经粘了 2.客户端没有粘,可能是在服务端粘了 首先需要掌握一个socket收发消息的原理 应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因.(因为TCP是流式协议,不知道啥时候开始,啥时候结束).而UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提

网络编程ssh,粘包

1.什么是socket? TCP,可靠地,面向连接协议,有阻塞rect udp,不可靠的,无线连接的服务 这里因为不需要阻塞,所以速度会很快,但安全性不高 2.关于客户端退出而服务器未退出的解决办法 1 import socket 2 sock=socket.socket() # TCP协议 3 IP_PORT=("127.0.0.1",8899) 4 sock.bind(IP_PORT) 5 sock.listen(5) 6 while 1: 7 conn,addr=sock.acc

网络编程 之粘包问题、使用socketserver实现并发

一.粘包问题 注意:粘包问题只有tcp协议并且udp协议永远不会粘包 粘包问题的产生: 简述:粘包问题的产生主要是由于tcp协议传输数据(其内置的nagle算法来进行的)会将数据较小的且发送时间较短的合并成一个包从发送端发送出去,接收端不知道该怎么去想要的数据拿出来这样造成了粘包问题,另一方面是由于时间太短接收端没有及时拿干净 传来的数据造成数据混乱(这是因为tcp协议又叫流氏协议指的是其就像水流一样传输数据)才产生的粘包问题. 1.发送端由于时间太短造成多个包合在一起发送产生粘包问题的实例如下

解决网络编程的粘包问题

# 服务端 import socketimport subprocessimport structimport json servers = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)servers.bind(('127.0.0.1', 7777))servers.listen(10)print('start settings') while True:    """连接循环""

python/socket编程之粘包

python/socket编程之粘包 粘包: 只有TCP有尿包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提取数据,当然也有可能是3k或者多k提取数据,也就是说,应用程序是不可见的,因此TCP协议是面来那个流的协议,这也是容易出现粘包的原因而UDP是面向笑死的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任一字节的数据,这一点和TCP是很同的.怎样定义消息呢?认为对方一次

Socket编程--TCP粘包问题

TCP是个流协议,它存在粘包问题 产生粘包的原因是: TCP所传输的报文段有MSS的限制,如果套接字缓冲区的大小大于MSS,也会导致消息的分割发送. 由于链路层最大发送单元MTU,在IP层会进行数据的分片. 应用层调用write方法,将应用层的缓冲区中的数据拷贝到套接字的发送缓冲区.而发送缓冲区有一个SO_SNDBUF的限制,如果应用层的缓冲区数据大小大于套接字发送缓冲区的大小,则数据需要进行多次的发送. 粘包问题的解决 ①:发送定长包 这里需要封装两个函数: ssize_t readn(int