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
//构造 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 #include #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 #include #include #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 #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 #include #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); }
### 完善版(使用环形缓冲区)
相对于“完整版”所改动的地方
databuffer.h
#ifndef NETDATABUFFER_H #define NETDATABUFFER_H
#define BUFFER_SIZE 1024 //初始缓冲区大小
class DataBuffer { public: char *m_pBuffer; //缓冲区 int m_nBufferSize; //缓冲区大小 int m_nStart; //数据开始位置 int m_nEnd; //数据结束位置 bool m_isFull; //缓冲区是否已满 bool m_isEmpty; //缓冲区是否为空
int getDataLen(); //获得缓冲区中数据大小
bool reBufferSize(int nLen); //调整缓冲区大小
bool addMsg(char *pBuf, int nLen); //添加消息到缓冲区
void poll(int nLen); //移除缓冲区首部的第一个数据包
void reset(); //缓冲区复位
public: DataBuffer(); ~DataBuffer(); };
#endif // NETDATABUFFER_H
databuffer.cpp
#include "databuffer.h" #include "string.h" #include
//构造 DataBuffer::DataBuffer() { m_nBufferSize = BUFFER_SIZE; //缓冲区大小 m_nStart = 0; //数据开始位置 m_nEnd = 0; //数据结束位置 m_isFull = false; //缓冲区是否已满 m_isEmpty = true; //缓冲区是否为空 m_pBuffer = new char[m_nBufferSize]; //分配缓冲区 memset(m_pBuffer, 0, sizeof(m_pBuffer)); //清空缓冲区 }
//析构 DataBuffer::~DataBuffer() { delete [] m_pBuffer; //释放缓冲区 m_pBuffer = NULL; m_nBufferSize = 0; }
//获得缓冲区中数据大小 int DataBuffer::getDataLen() { if(m_isFull) { return m_nBufferSize; } else if(m_nEnd < m_nStart) { return (m_nBufferSize - m_nStart) + m_nEnd; } else { return m_nEnd - m_nStart; } }
//重置缓冲区大小 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));
//将原缓冲区中的内容拷贝到新缓冲区
if(m_nStart < m_nEnd)
{
memcpy(m_pBuffer, oBuffer + m_nStart, m_nEnd - m_nStart);
}
else
{
int len1 = m_nBufferSize - m_nStart;
memcpy(m_pBuffer, oBuffer + m_nStart, len1);
memcpy(m_pBuffer + len1, oBuffer, m_nEnd);
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新