一. 客户端和服务器连接的步骤
1.项目配置
.pro文件夹network模块QT += core gui network sql
QT += core gui network sql
2.定义网络对象
Client函数中,定义QTcpSocket对象类型的成员变量m_socket
class Client : public QWidget
{
//...
public:
//
public slots:
//
private:
QTcpSocket m_socket;
//QTcpSocket 是 Qt 中用于 TCP 通信的核心类,定义为成员变量后,可在类的各个函数中操作 socket(连接、发送 / 接收数据等 )
};
3.连接
在client构造函数中,通过m_socket调用 m_socket.connectToHost(ip, port)发起连接到服务器,参数为ip和port成员变量(ip需要强转成QHostAddress)
4.结果打印
定义槽函数showConnect,打印连接服务器成功
5.关联信号与槽
在构造函数connect 绑定 connected 信号
Client::Client(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Client)
{
ui->setupUi(this);
loadConfig();
m_socket.connectToHost(QHostAddress(m_strIP),m_usPort);
// 信号槽关联:m_socket 发出 connected 信号时,调用当前类的 showConnect 槽函数
//1.谁发的信号2.发的什么信号3.谁处理的信号4.槽函数
connect(&m_socket,&QTcpSocket::connected,this,&Client::showConnect);
}
void Client::showConnect()
{
qDebug()<<"连接服务器成功";
}
客户端连接服务器完整流程:
1.项目配置加 network 模块 → 2. 定义 QTcpSocket 成员变量 → 3. 构造函数中调用 connectToHost(ip, port) 发起连接 → 4. 定义槽函数 showConnect 处理连接成功 → 5. 用 connect 关联 QTcpSocket::connected 信号与槽函数。
2. 创建一个单例模式的步骤
单例模式核心目标是保证一个类只有一个实例,并提供全局访问点。
1.私有化构造相关函数
私有化构造函数:防止外部直接 new Client 创建对象。
私有化拷贝构造函数和赋值运算符:防止通过拷贝或赋值创建新对象。
class Client : public QWidget
{
public:
//
public slots:
//
private:
//
// 私有化构造函数:外部无法直接 new Client
Client(QWidget *parent = nullptr);
// 私有化拷贝构造函数:禁止拷贝对象
Client(const Client& instance)=delete;
// 私有化赋值运算符:禁止对象赋值
Client& operator=(const Client&)=delete;
};
2. 定义静态获取
定义获取单例的静态函数,创建静态局部对象,并返回其引用
class Client : public QWidget
{
public:
static Client& getInstance();
//
Client &Client::getInstance()
{
static Client instance;
return instance;
}
3.通过静态函数创建 获取
main.cpp中创建的Client对象改为使用全局访问节点创建
Client::getInstance().show();
3. 创建一个pdu并给每个成员变量赋值的步骤
1.定义pdu结构体
struct PDU {//协议数据单元
unsigned int uiPDULen; // 协议总长度 = 结构体固定部分 + 柔性数组长度
unsigned int uiMsgLen; // 实际消息(柔性数组)的有效长度
unsigned int uiMsgType; // 消息类型(枚举区分,如注册请求/响应)
char caData[64]; // 固定参数(长度固定)
char caMsg[]; // 柔性数组(存实际消息,长度动态)
};
2.定义消息类型的枚举值
num ENUM_MSG_TYPE{//消息类型的枚举值
ENUM_MSG_TYPE_MIN=0,
ENUM_MSG_TYPE_REGIST_REQUEST,
ENUM_MSG_TYPE_REGIST_RESPOND,
ENUM_MSG_TYPE_MAX=0x00ffffff
};
3.定义沟通pdu函数,参数是消息长度
1.计算协议总长度 uiPDULen
2.根据长度申请空间,结果判空是否申请失败
3.初始化内存(memset赋 0)
4. pdu的两个长度赋值
记录实际消息长度(柔性数组有效长度)
记录协议总长度(固定部分 + 柔性数组)
PDU *mkPDU(uint uiMsgType,uint uiMsgLen)
{
uint uiPDULen=uiMsgLen+sizeof(PDU);//实际消息长度+pdu结构体长度
PDU* pdu = (PDU*)malloc(uiPDULen);//动态分配内存,申请 uiPDULen 大小的内存,强制转换为 PDU* 类型,让 pdu 指向可容纳结构体固定部分 + 柔性数组的内存块。
if (pdu == NULL) {
exit(1);
}
memset(pdu, 0, uiPDULen);
pdu->uiMsgLen=uiMsgLen;
pdu->uiPDULen=uiPDULen;
pdu->uiMsgType=uiMsgType;
return pdu;
}
4. memcpy函数的每个参数的含义和怎么传
memcpy函数原型
void* memcpy(void* destination, const void* source, size_t num);
目标地址 源地址
memcpy(pdu->caMsg, strMsg.toStdString().c_str(), strMsg.toStdString().size());
往pdu中存东西怎么传
void Client::on_send_PB_clicked()
{
QString strMsg = ui->input_LE->text();
if (strMsg.isEmpty()) {
return;
}
PDU* pdu = mkPDU(strMsg.toStdString().size() + 1);
pdu->uiMsgType = ENUM_MSG_TYPE_REGIST_REQUEST;
memcpy(pdu->caMsg, strMsg.toStdString().c_str(), strMsg.toStdString().size());
m_socket.write((char*)pdu, pdu->uiPDULen);
qDebug() << "send msg uiPDULen" << pdu->uiPDULen
<< "uiMsgLen" << pdu->uiMsgLen
<< "uiMsgType" << pdu->uiMsgType
<< "caData" << pdu->caData
<< "caMsg" << pdu->caMsg;
free(pdu);
pdu = NULL;
}
5. conncet函数每个参数的函数和怎么传
QMetaObject::Connection connect(
const QObject *sender, // 发送信号的对象
PointerToMemberFunction signal, // 信号的成员函数指针
const QObject *receiver, // 接收信号的对象
PointerToMemberFunction method, // 槽函数的成员函数指针
Qt::ConnectionType type = Qt::AutoConnection // 连接类型,可选
);
connect(this, &QTcpSocket::readyRead, this, &MyTcpSocket::recvMsg);
发送信号的对象 信号成员函数指针 接收信号对象 槽函数的成员函数指针
从pdu 中取东西怎么传
MyTcpSocket::MyTcpSocket()
{
// 关联接收到消息的信号和处理接收的函数
connect(this, &QTcpSocket::readyRead, this, &MyTcpSocket::recvMsg);
}
void MyTcpSocket::recvMsg()
{
qDebug() << "recvMsg 接收消息长度: " << this->bytesAvailable();
unsigned int uiPDULen = 0;
this->read((char*)&uiPDULen, sizeof(unsigned int));
PDU* pdu = mkPDU(uiPDULen - sizeof(PDU));
this->read((char*)(pdu + sizeof(unsigned int)), uiPDULen - sizeof(unsigned int));
qDebug() << "recvMsg uiPDULen" << uiPDULen
<< "uiMsgLen" << pdu->uiMsgLen
<< "uiMsgType" << pdu->uiMsgType
<< "caData" << pdu->caData
<< "caMsg" << pdu->caMsg;
free(pdu);
pdu = NULL;
}