四. 网络编程(TCP 黏包)

一 .黏包现象(TCP)

1.黏包成因

TCP协议中的数据传递
tcp协议的拆包机制
当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去。
MTU是Maximum Transmission Unit的缩写。意思是网络上传送的最大数据包。MTU的单位是字节。 大部分网络设备的MTU都是1500。如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多数据包碎片,增加丢包率,降低网络速度
面向流的通信特点和Nagle算法

TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。
收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。
这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。
对于空消息:tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,udp协议会帮你封装上消息头发送过去。
可靠黏包的tcp协议:tcp的协议数据不会丢,没有收完包,下次接收,会继续上次继续接收,己端总是在收到ack时才会清除缓冲区内容。数据是可靠的,但是会粘包。


udp是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,udp协议会帮你封装上消息头发送过去。
不可靠不黏包的udp协议:udp的recvfrom是阻塞的,一个recvfrom(x)必须对唯一一个sendinto(y),收完了x个字节的数据就算完成,若是y;x数据就丢失,这意味着udp根本不会粘包,但是会丢数据,不可靠
subprocess模块是python从2.4版本开始引入的模块。
让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)import subprocess
# subprocess模块是python从2.4版本开始引入的模块。
# 主要用来取代 一些旧的模块方法,如os.system、os.spawn*、os.popen*、commands.*等。subprocess通过子进程来执行外部指令
cmd=subprocess.Popen("dir",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print(cmd.stderr.read().decode("gbk"))
print(cmd.stdout.read().decode("gbk"))

2.基于tcp协议实现的黏包

server1我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)
import  socket
# import  subprocess
server=socket.socket()
server.bind(("192.168.59.1",8600))
server.listen(5)

conn,addr=server.accept()
while True:
       cmd = input("请输入你终端命令:")
       conn.send(cmd.encode("utf-8"))

       ret = conn.recv(1024)
       print(ret.decode("utf-8"),"这是服务器哈哈哈")
conn.close()
server.close()
client1
我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)

import  socket
import subprocess

client=socket.socket()
client.connect(("192.168.59.1",8600))
while True:
        msg=client.recv(1024)
        ret = subprocess.Popen(msg.decode(‘gbk‘), shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)

        err=‘我是err‘+(ret.stderr.read()).decode("gbk")
        out=‘我是out‘+(ret.stderr.read()).decode("gbk")
        print(err)
        print(out)
        client.send(err.encode("utf-8"))
        client.send(out.encode("utf-8"))

        print(msg.decode("utf-8"))
client.close()
server2

from socket import *
import subprocess
ip_port=(‘127.0.0.1‘,8888)
server=socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server.bind(ip_port)
server.listen(5)
while True:
    conn,addr=server.accept()
    print(‘客户端‘,addr)
    while True:
        cmd=conn.recv(1024)
        if len(cmd) == 0:break
        res=subprocess.Popen(cmd.decode(‘utf-8‘),shell=True,
                         stdout=subprocess.PIPE,
                         stdin=subprocess.PIPE,
                         stderr=subprocess.PIPE)
        stderr=res.stderr.read()
        stdout=res.stdout.read()
        conn.send(stderr)
        conn.send(stdout)
client1

import socket
ip_port=(‘127.0.0.1‘,8888)
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(ip_port)
while True:
    msg=input(‘请输入命令哈: ‘).strip()
    if len(msg) == 0:continue
    if msg == ‘quit‘:break

    s.send(msg.encode(‘utf-8‘))

    act_res=s.recv(1024)
    print(act_res.decode(‘utf-8‘),end=‘‘)

情况二 接收方的缓存机制

接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)

总结

黏包现象只发生在tcp协议中:

1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。

2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

原文地址:https://www.cnblogs.com/Sup-to/p/11135465.html

时间: 2024-08-30 07:52:15

四. 网络编程(TCP 黏包)的相关文章

网络编程之黏包

当我们同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种现象就是黏包. 黏包成因 TCP协议中的数据传递: tcp协议的拆包机制 当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去. MTU是Maximum Transmission Unit的缩写.意思是网络上传送的最大数据包.MTU的单位是字节. 大部分网络设备的MTU都是1500.如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会

《Python》网络编程之黏包

黏包 一.黏包现象 同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包. server端 import socket sk = socket.socket() sk.bind(('127.0.0.1', 9000)) sk.listen() conn, addr = sk.accept() conn.send(b'hello,') conn.send(b'world') conn.close() client端 import

五十四 网络编程 TCP编程

Socket是网络编程的一个抽象概念.通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可. 客户端 大多数连接都是可靠的TCP连接.创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器. 举个例子,当我们在浏览器中访问新浪时,我们自己的计算机就是客户端,浏览器会主动向新浪的服务器发起连接.如果一切顺利,新浪的服务器接受了我们的连接,一个TCP连接就建立起来的,后面的通信就是发送网页内容了. 所以,我们要

网络编程中黏包的解决方案

解决方案一 问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据. #_*_coding:utf-8_*_ import socket,subprocess ip_port=('127.0.0.1',8080) s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.setsockopt(socket.SOL_

网络编程- 解决黏包现象方案一(六)

队列 利用队列的思路来解决黏包问题 总结 原文地址:https://www.cnblogs.com/mys6/p/10797907.html

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

server端 import jsonimport structimport socket sk = socket.socket()sk.bind(('127.0.0.1',8080))sk.listen() conn,addr = sk.accept()dic_len = conn.recv(4) # 4个字节 数字的大小dic_len = struct.unpack('i',dic_len)[0]content = conn.recv(dic_len).decode('utf-8') # 7

python网络编程——TCP

<pre name="code" class="python"> 一.网络通信模式 对于网络通信,现在遵循的是TCP/IP协议组. 而现在设计的通信模式中,主要使用的是客户端/服务器编程,所谓的客户端就是我们用户所用的软件,而服务端则是程序开发人员根据客户端的需要设计的服务模式,为了是满足客户端的要求,实现和客户端进行正常通信. 二.套接字:通信的端点 对于tcp/Ip协议来说,它是一个多层协议族,分别是物理层,数据链路层,网络层,传输层,应用层.对于网

网络编程TCP总结及实践-C语言

网络变成首先要注意IP和端口的转换,现在电脑基本上是主机字节序,存储按照小端方式,而在网络中传输统一使用大端方式,所以网络变成首先要注意字节序的转换. 一个常用的ip转换程序的实现: #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #define CHIP(ip) (ip&0xff)<<24 |(ip&(0xff<&

netty]--最通用TCP黏包解决方案

netty]--最通用TCP黏包解决方案:LengthFieldBasedFrameDecoder和LengthFieldPrepender 2017年02月19日 15:02:11 惜暮 阅读数:14555 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u010853261/article/details/55803933 前面已经说过: TCP以流的方式进行数据传输,上层应用协议为了对消息进行区分,往往采用如下4种方式. (1)消息长度固定