收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
粘包处理后
服务器端
#pragma pack(push, 1) //按照1字节对齐
typedef struct
{
int len; //包头,包体长度
char data[1024]; //包体
}NetPacket;
#pragma pack(pop)
//出现一个新连接时调用
void myTcpServer::incomingConnection(int socketDescriptor)
{
clientConnection = new QTcpSocket;
clientConnection->setSocketDescriptor(socketDescriptor);
char *d1 = "data1";
char *d2 = "data2";
char *d3 = "data3";
NetPacket p1, p2, p3;
p1.len = sizeof("data1"); //封装第一个数据包
memcpy(p1.data, d1, p1.len);
p2.len = sizeof("data2");
memcpy(p2.data, d2, p2.len);
p3.len = sizeof("data3");
memcpy(p3.data, d3, p3.len);
clientConnection->write((char *)&p1, sizeof(int) + p1.len); //发送数据包
clientConnection->write((char *)&p2, sizeof(int) + p2.len);
clientConnection->write((char *)&p3, sizeof(int) + p3.len);
}
客户端
void myTcpClient::slotRead()
{
while(tcpSocket->bytesAvailable()>0)
{
int len;
char buf[1024]; //接收数据的缓冲区
char tmpBuf[1024]; //存放包体
int nOffset = 0; //偏移
int n = tcpSocket->bytesAvailable(); //接收到的字节数
tcpSocket->read(buf, n);
memcpy(&len, buf, sizeof(int)); //包头:包体长度
nOffset += sizeof(int);
memcpy(tmpBuf, buf+nOffset, len); //包体
nOffset += len;
printf("%s\n", tmpBuf); //打印包体
memcpy(&len, buf, sizeof(int));
nOffset += sizeof(int);
memcpy(tmpBuf, buf+nOffset, len);
nOffset += len;
printf("%s\n", tmpBuf);
memcpy(&len, buf, sizeof(int));
nOffset += sizeof(int);
memcpy(tmpBuf, buf+nOffset, len);
nOffset += len;
printf("%s\n", tmpBuf);
}
}
运行结果:
完整版
服务器端和客户端共有的文件
databuffer.h
#ifndef NETDATABUFFER_H
#define NETDATABUFFER_H
#define BUFFER_SIZE 1024 //初始缓冲区大小
class DataBuffer
{
public:
char *m_pBuffer; //缓冲区
int m_nBufferSize; //缓冲区大小
int m_nOffset; //缓冲区中当前数据大小
int getDataLen(); //获得缓冲区中数据大小
bool reBufferSize(int nLen); //调整缓冲区大小
bool addMsg(char *pBuf, int nLen); //添加消息到缓冲区
void reset(); //缓冲区复位
void poll(int nLen); //移除缓冲区首部的第一个数据包
public:
DataBuffer();
~DataBuffer();
};
#endif // NETDATABUFFER_H
databuffer.cpp
#include "databuffer.h"
#include "string.h"
#include <QException>
//构造
DataBuffer::DataBuffer()
{
m_nBufferSize = BUFFER_SIZE; //缓冲区大小
m_nOffset = 0; //缓冲区当前现有数据大小
m_pBuffer = new char[m_nBufferSize]; //分配缓冲区
memset(m_pBuffer, 0, sizeof(m_pBuffer)); //清空缓冲区
}
//析构
DataBuffer::~DataBuffer()
{
delete [] m_pBuffer; //释放缓冲区
m_pBuffer = NULL;
m_nBufferSize = 0;
m_nOffset = 0;
}
//获得缓冲区中数据大小
int DataBuffer::getDataLen()
{
return m_nOffset;
}
//重置缓冲区大小
bool DataBuffer::reBufferSize(int nLen)
{
char *oBuffer = m_pBuffer; //保存原缓冲区地址
try
{
nLen = nLen < 64 ? 64: nLen; //保证最小大小
while(m_nBufferSize < nLen)
{
m_nBufferSize *= 2;
}
m_pBuffer = new char[m_nBufferSize]; //分配新缓冲区
memset(m_pBuffer, 0, sizeof(m_pBuffer));
memcpy(m_pBuffer, oBuffer, m_nOffset); //将原缓冲区中的内容拷贝到新缓冲区
delete []oBuffer; //释放原缓冲区
}
catch(QException e)
{
return false;
}
return true;
}
//向缓冲区中添加消息
/*
* pBuf,要添加的数据
* nLen,数据长度
* 成功返回true,失败返回false
*/
bool DataBuffer::addMsg(char *pBuf, int nLen)
{
try
{
if(m_nOffset + nLen > m_nBufferSize) //如果缓冲过小,重新调整其大小
reBufferSize(m_nOffset + nLen);
memcpy(m_pBuffer + m_nOffset, pBuf, nLen); //将新数据拷贝到缓冲区尾
m_nOffset += nLen; //修改数据偏移
}
catch(QException e)
{
return false;
}
return true;
}
//缓冲区复位
void DataBuffer::reset()
{
if(m_nOffset > 0)
{
memset(m_pBuffer, 0, sizeof(m_pBuffer));
m_nOffset = 0;
}
}
//移除缓冲区首部第一个数据包
//nLen:一个数据包的大小
void DataBuffer::poll(int nLen)
{
if(m_nOffset == 0 || m_pBuffer == NULL)
return;
if(m_nOffset >= nLen)
{
memcpy(m_pBuffer, m_pBuffer + nLen, m_nOffset - nLen);
m_nOffset -= nLen;
}
}
netcom.h
#ifndef NETTEMPLATE_H
#define NETTEMPLATE_H
#include <QTcpSocket>
#include <QDebug>
#include "databuffer.h"
#pragma pack(push, 1) //采用1字节对齐方式
//包头
typedef struct
{
int nLen; //包体长度
}PacketHead;
//封包对象:包头 + 包体
typedef struct
{
PacketHead head; //包头
char *body; //包体
}Packet;
#pragma pack(pop)
class NetComTemplate
{
public:
QTcpSocket *m_tcpSocket; //通信套接字
DataBuffer m_Buffer; //套接字关联的缓冲区
void packData(char *data, int nLen); //封包,发送
void unpackData(char *data, int nLen); //将接收到的数据放在缓冲区后,解包
virtual void recv(char *data); //每解完一包之后的处理,留给继承的类去实现
NetComTemplate();
~NetComTemplate();
};
#endif // NETTEMPLATE_H
netcom.cpp
#include "netcom.h"
NetComTemplate::NetComTemplate()
{
}
NetComTemplate::~NetComTemplate()
{
}
//封包,发送
//data: 要发送的数据
//nLen: 要发送数据的长度
void NetComTemplate::packData(char *data, int nLen)
{
Packet p;
int headLen = sizeof(PacketHead); //包头大小
p.head.nLen = nLen; //包体大小
char *buf = new char[headLen + nLen];
memcpy(buf, &p.head, headLen); //包头
memcpy(buf + headLen, data, nLen); //包体
if(m_tcpSocket != NULL)
m_tcpSocket->write(buf, headLen + nLen); //发包
else
qDebug() << "socket 未建立!";
}
//解包
//data: 要发送的数据
//nLen: 要发送数据的长度
void NetComTemplate::unpackData(char *data, int nLen)
{
m_Buffer.addMsg(data, nLen); //添加数据到缓冲区
int totalLen = m_Buffer.getDataLen(); //缓冲区中数据大小
int headLen = sizeof(PacketHead); //包头大小
while(totalLen > 0)
{
//不够包头,不处理
if(totalLen < headLen)
{
break;
}
Packet pack; //接收到的包
memcpy(&pack.head, m_Buffer.m_pBuffer, headLen); //包头
int bodyLen = pack.head.nLen; //包体大小
int packLen = headLen + bodyLen; //一包数据大小
if(totalLen < packLen) //不够一包数据,等够了再解析
{
break;
}
//数据足够多
pack.body = new char[bodyLen];
memcpy(pack.body, m_Buffer.m_pBuffer + headLen, bodyLen); //包体
recv(pack.body); //处理得到的包体
m_Buffer.poll(packLen); //移除缓冲区中第一个数据包
totalLen -= (packLen);
}
}
//留给继承的类去实现
//buf: 解包后得到的包体
void NetComTemplate::recv(char *data)
{
}
服务器端
tcpserver.h
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include <QTcpServer>
#include <QTcpSocket>
#include <QObject>
#include "netcom.h"
class myTcpServer : public QTcpServer, public NetComTemplate
{
Q_OBJECT
public:
myTcpServer(QObject *parent, int port);
~myTcpServer();
protected:
void incomingConnection(int socketDescriptor);
};
#endif // TCPSERVER_H
tcpserver.cpp
#include "tcpserver.h"
#include <QDataStream>
#include <stdlib.h>
myTcpServer::myTcpServer(QObject *parent, int port): QTcpServer(parent)
{
listen(QHostAddress::Any, port);
}
myTcpServer::~myTcpServer()
{
}
//出现一个新连接时调用
void myTcpServer::incomingConnection(int socketDescriptor)
{
m_tcpSocket = new QTcpSocket;
m_tcpSocket->setSocketDescriptor(socketDescriptor);
char *d1 = "data1";
char *d2 = "data2";
char *d3 = "data3";
packData(d1, sizeof("data1")); //封包,发送
packData(d2, sizeof("data2"));
packData(d3, sizeof("data3"));
}
客户端
tcpclient.h
#ifndef MYTCPCLIENT_H
#define MYTCPCLIENT_H
#include <QTcpSocket>
#include <QtNetwork>
#include "netcom.h"
class myTcpClient : public QObject, public NetComTemplate
{
Q_OBJECT
public:
myTcpClient(QObject *parent = 0);
~myTcpClient();
void recv(char *data); //每解完一包之后的处理
public slots:
void slotRead();
};
#endif // MYTCPCLIENT_H
tcpclient.cpp
#include "tcpclient.h"
myTcpClient::myTcpClient(QObject *parent) : QObject(parent)
{
m_tcpSocket = new QTcpSocket;
connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(slotRead()));
m_tcpSocket->connectToHost(QHostAddress("127.0.0.1"), 8180);
}
myTcpClient::~myTcpClient()
{
}
void myTcpClient::slotRead()
{
while(m_tcpSocket->bytesAvailable()>0)
{
int n = m_tcpSocket->bytesAvailable(); //接收到的字节数
char *buf = new char[n];
m_tcpSocket->read(buf, n); //读取数据
unpackData(buf, n); //解包
delete []buf;
}
}
//解包之后的处理
void myTcpClient::recv(char *data)
{
printf("%s\n", data);
}
完善版(使用环形缓冲区)
相对于“完整版”所改动的地方
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
et->read(buf, n); //读取数据
unpackData(buf, n); //解包
delete []buf;
}
}
//解包之后的处理
void myTcpClient::recv(char *data)
{
printf(“%s\n”, data);
}
### 完善版(使用环形缓冲区)
相对于“完整版”所改动的地方
[外链图片转存中...(img-mhsaVU8G-1715721114036)]
[外链图片转存中...(img-DLwxX97A-1715721114037)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**