封装一个带大小的封包,防止Tcp粘包、拆包

C++

头文件

#ifndef TCPWRAP_H
#define TCPWRAP_H

#include <memory>
#include <netinet/in.h>
#include <string.h>

#pragma pack(push,1)

typedef struct
{
    size_t length;  //包头(包体长度)
    char* body; //包体
}Packet;

#pragma pack(pop)

class TcpDataWrap
{
private:
    static TcpDataWrap* m_instance;
    TcpDataWrap();

public:
    static TcpDataWrap* instance();

    void sendPackData(int sockfd,char* data,int nLen);

    std::shared_ptr<char> recvUnpackData (int sockfd);

};

#endif

源文件

#include "tcpwrap.h"
#include <iostream>
using namespace std;

TcpDataWrap* TcpDataWrap::m_instance = NULL;

TcpDataWrap* TcpDataWrap::instance()
{
    if(m_instance == NULL)
    {
        m_instance = new TcpDataWrap();
    }
    return m_instance;
}

TcpDataWrap::TcpDataWrap() {}

void TcpDataWrap::sendPackData(int sockfd,char* data,int nLen)
{
    Packet p;
    size_t headSize = sizeof(size_t);
    p.length = nLen;

    size_t totalLen = headSize + nLen;

    char* buf = new char[totalLen];
    memcpy(buf, &p.length, headSize);
    memcpy(buf + headSize, data, nLen);
    send(sockfd, buf, totalLen,0);
}

//返回一个指向char*的智能指针
std::shared_ptr<char> TcpDataWrap::recvUnpackData (int sockfd)
{
    size_t byteRead=0;
    size_t bodyLen = 0;
    while (byteRead <sizeof(size_t))
    {
        byteRead = recv(sockfd, &bodyLen, sizeof(size_t), MSG_PEEK);    //查看数据长度是否满足头文件的要求
    }
    recv(sockfd, &bodyLen, sizeof(size_t), 0);

    char* data = new char[bodyLen];
    char* pData = data;

    size_t byteLeft = bodyLen;

    while (byteLeft>0)
    {
        byteRead = recv(sockfd, data, byteLeft, 0);
        byteLeft -= byteRead;
        pData += byteRead;
    }
    std::shared_ptr<char> ret(data);
    return ret;
}

QT

头文件

#ifndef TCPWRAP_H
#define TCPWRAP_H

#include <memory>
#include <string.h>
#include <QTcpSocket>

#pragma pack(push,1)

typedef struct
{
    size_t length;  //包头(包体长度)
    char* body; //包体
}Packet;

#pragma pack(pop)

class TcpDataWrap : public QObject
{
public:
    static TcpDataWrap* instance();
    void sendPackData(QTcpSocket* sockfd, char* data, int nLen);
    std::shared_ptr<char> recvUnpackData (QTcpSocket* sockfd);

private:
    TcpDataWrap();
    static TcpDataWrap* m_instance;
};

#endif // TCPWRAP_H

源文件

#include "tcpwrap.h"
#include <QTcpSocket>

TcpDataWrap* TcpDataWrap::m_instance = nullptr;

TcpDataWrap* TcpDataWrap::instance()
{
    if(m_instance == nullptr)
    {
        m_instance = new TcpDataWrap();
    }
    return  m_instance;
}

TcpDataWrap::TcpDataWrap(){}

void TcpDataWrap::sendPackData(QTcpSocket* sockfd, char* data, int nLen)
{
    Packet p;
    size_t headSize = sizeof(size_t);
    p.length = nLen;
    size_t totalLen = headSize+nLen;
    char* buf = new char[totalLen];
    memset(buf,0,totalLen);
    memcpy(buf,&p.length,headSize);
    memcpy(buf+headSize,data,nLen);
    sockfd->write(buf,totalLen);
}

std::shared_ptr<char> TcpDataWrap::recvUnpackData (QTcpSocket* sockfd)
{
    size_t byteRead = 0;
    size_t bodyLen;
    while (byteRead<sizeof (size_t))
    {
        byteRead=sockfd->bytesAvailable();
    }

    sockfd->read((char*)&bodyLen,sizeof (size_t));
    char* data = new char[bodyLen];
    char* pData = data;
    size_t byteLeft = bodyLen;
    while (byteLeft>0)
    {
        byteRead=sockfd->read(data,byteLeft);
        byteLeft -= byteRead;
        pData += byteRead;
    }

    std::shared_ptr<char> ret(data);
    return  ret;
}

原文地址:https://www.cnblogs.com/WindSun/p/12317108.html

时间: 2024-10-27 21:19:24

封装一个带大小的封包,防止Tcp粘包、拆包的相关文章

TCP粘包/拆包问题

无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包/拆包 TCP是个"流"协议,所谓流,就是没有界限的一串数据.大家可以想想河里的流水,是连成一片的,其间并没有分界线.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题. TCP粘包/拆包问题说明 假设客户

Netty(三)TCP粘包拆包处理

tcp是一个“流”的协议,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题. 粘包.拆包问题说明 假设客户端分别发送数据包D1和D2给服务端,由于服务端一次性读取到的字节数是不确定的,所以可能存在以下4种情况. 1.服务端分2次读取到了两个独立的包,分别是D1,D2,没有粘包和拆包: 2.服务端一次性接收了两个包,D1和D2粘在一起了,被成为TCP粘包; 3.服务端分2次读取到了两个数据包,第一次读取到了完整的D1和D2包的部

TCP 粘包/拆包问题

简介 TCP 是一个’流’协议,所谓流,就是没有界限的一串数据. 大家可以想想河里的流水,是连成一片的.期间并没有分界线, TCP 底层并不了解上层业务数据的具体含义 ,它会根据 TCP 缓冲区的实际情况进行包得划分,所以在业务上认为,一个完整的包可能会被 TCP 拆分成多个包进行发送 . 也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的 TCP 拆包和粘包. TCP 粘包/拆包问题说明 我们可以通过图解对 TCP 粘包和拆包进行说明.粘包问题示例图: 假设客户端分别发送了两个数据包

【游戏开发】Netty TCP粘包/拆包问题的解决办法(二)

上一篇:[Netty4.X]Unity客户端与Netty服务器的网络通信(一) 一.什么是TCP粘包/拆包 如图所示,假如客户端分别发送两个数据包D1和D2给服务端,由于服务端一次读取到的字节数是不确定的,故可能存在以下4中情况: 第一种情况:Server端分别读取到D1和D2,没有产生粘包和拆包的情况. 第二种情况:Server端一次接收到两个数据包,D1和D2粘合在一起,被称为TCP粘包. 第三种情况:Server端分2次读取到2个数据包,第一次读取到D1包和D2包的部分内容D2_1,第二次

Netty学习之TCP粘包/拆包

一.TCP粘包/拆包问题说明,如图 二.未考虑TCP粘包导致功能异常案例 按照设计初衷,服务端应该收到100条查询时间指令的请求查询,客户端应该打印100次服务端的系统时间 1.服务端类 package com.phei.netty.s2016042302; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitial

netty解决tcp粘包拆包问题

tcp粘包拆包解决方案 1.发送定长的消息 server端:                    EventLoopGroup pGroup = new NioEventLoopGroup(); EventLoopGroup cGroup = new NioEventLoopGroup(); ServerBootstrap b = new ServerBootstrap(); b.group(pGroup, cGroup)  .channel(NioServerSocketChannel.cl

Netty的TCP粘包/拆包(源码二)

假设客户端分别发送了两个数据包D1和D2给服务器,由于服务器端一次读取到的字节数是不确定的,所以可能发生四种情况: 1.服务端分两次读取到了两个独立的数据包,分别是D1和D2,没有粘包和拆包. 2.服务端一次接收到了两个数据包,D1和D2粘合在一起,被称为TCP粘包. 3.服务端分两次读取到了两个数据包,第一次读取到了完整的D1包和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为TCP拆包. 4.服务端分两次读取到了两个数据包,第一次读取到了D1包的部分内容D1_1,第二次读取到了D1

netty权威指南--------第四章TCP粘包/拆包问题

第三章中的示例用于功能测试一般没有问题,但当压力上来或者发送大报文时,就会存在粘包/拆包问题. 这时就需要使用LineBasedFrameDecoder+StringDecoder client端请求改为连续的100次 package com.xiaobing.netty.fourth; import java.net.SocketAddress; import org.omg.CORBA.Request; import io.netty.buffer.ByteBuf; import io.ne

一起学Netty(七)之 TCP粘包拆包基本解决方案

上个小节我们浅析了在Netty的使用的时候TCP的粘包和拆包的现象,Netty对此问题提供了相对比较丰富的解决方案 Netty提供了几个常用的解码器,帮助我们解决这些问题,其实上述的粘包和拆包的问题,归根结底的解决方案就是发送端给远程端一个标记,告诉远程端,每个信息的结束标志是什么,这样,远程端获取到数据后,根据跟发送端约束的标志,将接收的信息分切或者合并成我们需要的信息,这样我们就可以获取到正确的信息了 例如,我们刚才的例子中,我们可以在发送的信息中,加一个结束标志,例如两个远程端规定以行来切