QTcpSocket 发送数据心得

在QT开发中,使用QTcpSocket进行TCP通信时,如何正确发送数组或结构体是个挑战。避免使用数据流,因为它会修改char数组的值。尝试将char数组转换为QString再利用QTcpSocket的write函数,例如write(const char *, qint64),可以有效防止数据篡改。同时,确保在写入前清空指针缓存以保证内容正确。" 102941731,8082822,在线考试破解:解除浏览器屏蔽功能技巧,"['前端开发', 'JavaScript', '浏览器', '安全', '教育技术']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

遇到不会用的函数前,最好还是看看手册QAQ,今天居然吃了这个大亏!!!
先交代一下背景:
在做TCP客户端的发送数据功能,要和服务器程序进行TCP/IP通信,且根据通信协议要发送数组或者结构体,并且数组的每一个位都是有效数据位。因此不能像大多数人一样加blockSize篡改协议内容。。

网上大多数的例子都是

    //用于暂存要发送的数据  
    QByteArray block;  
    //使用数据流写入数据  
    QDataStream out(&block,QIODevice::ReadWrite);  
    //设置数据流的版本,客户端和服务器端使用的版本要相同  
    out.setVersion(QDataStream::Qt_4_6);  

    //设置发送长度初始值为0  
    out << (quint16) 0;  
    //设置发送内容  
    out<<hash;  

    //回到字节流起始位置  
    
<think>我们使用QTcpSocket发送JSON数据的步骤: 1. 创建QTcpSocket对象并连接到服务器。 2. 构建JSON数据(使用QJsonObject和QJsonDocument)。 3. 将JSON文档转换为QByteArray(通常使用toJson()方法)。 4. 通过QTcpSocket的write()方法发送该数据。 5. 如果需要,可以添加错误处理和连接状态的处理。 注意:由于TCP是流式传输,我们需要考虑如何界定数据包。常见做法有: - 在每个JSON数据包前面加上长度前缀(推荐)。 - 使用特定的分隔符(如换行符,但要求JSON数据中不能有换行)。 以下示例采用长度前缀的方法:先发送4个字节(quint32)表示JSON数据的长度,再发送JSON数据。 示例代码: 假设我们要发送一个JSON对象:{"command": "login", "username": "user1", "password": "pass123"} 步骤: 1. 创建QTcpSocket对象并连接服务器。 2. 构建JSON对象并转换为QByteArray。 3. 计算该QByteArray的长度(字节数),并转换为网络字节序(大端序)的4字节数据。 4. 先发送长度,再发送JSON数据。 注意:网络字节序转换使用qToBigEndian函数。 代码示例: */ #include <QTcpSocket> #include <QJsonObject> #include <QJsonDocument> #include <QByteArray> #include <QtEndian> // 用于字节序转换 // ... // 创建socket并连接服务器 QTcpSocket *socket = new QTcpSocket(); socket->connectToHost("127.0.0.1", 1234); if (socket->waitForConnected()) { // 构建JSON对象 QJsonObject json; json["command"] = "login"; json["username"] = "user1"; json["password"] = "pass123"; // 将JSON对象转换为文档 QJsonDocument jsonDoc(json); QByteArray jsonData = jsonDoc.toJson(QJsonDocument::Compact); // 紧凑格式,无换行 // 计算数据长度(4字节,quint32) quint32 dataSize = static_cast<quint32>(jsonData.size()); // 将长度转换为网络字节序(大端序) quint32 netSize = qToBigEndian(dataSize); // 构造要发送的数据:先发送长度(4字节),再发送JSON数据 QByteArray block; block.append(reinterpret_cast<const char*>(&netSize), sizeof(quint32)); block.append(jsonData); // 发送数据 socket->write(block); socket->flush(); // 立即发送 // 注意:实际应用中需要处理发送错误和超时等情况 } else { // 连接失败处理 qDebug() << "连接失败:" << socket->errorString(); } // 注意:在真实应用中,需要管理socket的生命周期,并处理断开连接等情况。 /* 接收方处理: 接收方需要先读取4个字节,将其转换为quint32(本地字节序),然后读取对应长度的JSON数据,再解析。 注意:上述代码中,我们使用了waitForConnected()进行阻塞等待连接,在实际应用中,我们可能使用异步方式(信号槽)来处理连接和发送。 另外,如果发送的数据量很大,可能需要分多次发送,但上述代码中,我们假设一次write就可以发送完。如果数据量很大,应该检查write的返回值,确保所有数据都被发送。 以上是一个简单的示例,实际应用中需要更完善的错误处理和连接管理。 引用说明: 我们参考了Qt中关于QTcpSocket和JSON处理的相关知识,以及常见的网络通信模式[^1][^3]。 */ §§相关问题§§ 1. 如何接收使用长度前缀的JSON数据? 2. QTcpSocket发送数据时,如何确保大数据量的可靠传输? 3. 除了长度前缀,还有哪些方法可以解决TCP粘包问题? 4. 如何异步处理QTcpSocket的连接和发送?</think>### QTcpSocket 发送 JSON 数据示例代码 以下是使用 QTcpSocket 发送 JSON 数据的完整实现步骤和代码示例: --- #### **核心步骤** 1. **创建 JSON 对象**:使用 `QJsonObject` 封装数据 2. **序列化 JSON**:用 `QJsonDocument` 转换为字节数组 3. **添加长度前缀**:解决 TCP 粘包问题 4. **通过 Socket 发送**:使用 `QTcpSocket::write()` 传输数据 --- #### **完整代码示例** ```cpp #include <QTcpSocket> #include <QJsonObject> #include <QJsonDocument> // 创建 TCP Socket 并连接服务器 QTcpSocket *socket = new QTcpSocket; socket->connectToHost("127.0.0.1", 8080); // 替换为实际 IP 和端口 if (socket->waitForConnected(3000)) { // 等待连接 // 1. 构建 JSON 数据 QJsonObject json; json["command"] = "login"; json["username"] = "user123"; json["password"] = "pass456"; // 2. 序列化为 JSON 字节数组 QJsonDocument jsonDoc(json); QByteArray jsonData = jsonDoc.toJson(QJsonDocument::Compact); // 紧凑格式 // 3. 添加 4 字节长度前缀 (大端序) quint32 dataSize = static_cast<quint32>(jsonData.size()); QByteArray block; block.append(reinterpret_cast<char*>(&dataSize), sizeof(quint32)); block.append(jsonData); // 4. 发送数据 socket->write(block); socket->flush(); // 立即发送缓冲区数据 qDebug() << "已发送 JSON 数据:" << jsonData; } else { qDebug() << "连接失败:" << socket->errorString(); } // 释放资源 (实际应用中应在对象生命周期结束时释放) // delete socket; ``` --- #### **关键说明** 1. **长度前缀机制** - 在 JSON 数据前添加 `quint32` 类型(4 字节)的长度信息 - 接收方需先读取长度头,再按长度获取完整数据 - 解决 TCP 流式传输的粘包问题[^1] 2. **JSON 序列化** - `QJsonDocument::Compact` 生成无空格压缩格式 - 可选 `QJsonDocument::Indented` 生成可读格式(调试用) 3. **错误处理建议** ```cpp connect(socket, &QTcpSocket::errorOccurred, [](QAbstractSocket::SocketError error) { qDebug() << "Socket 错误:" << error; }); ``` --- #### **接收方处理逻辑** ```cpp // 接收端伪代码示例 QByteArray buffer; // 读取长度前缀 if (buffer.size() >= 4) { quint32 jsonSize; memcpy(&jsonSize, buffer.constData(), 4); jsonSize = qFromBigEndian(jsonSize); // 转换字节序 // 检查是否收到完整 JSON if (buffer.size() >= jsonSize + 4) { QByteArray jsonData = buffer.mid(4, jsonSize); QJsonDocument doc = QJsonDocument::fromJson(jsonData); QJsonObject obj = doc.object(); // 处理 JSON 数据... buffer.remove(0, jsonSize + 4); // 清除已处理数据 } } ``` --- #### **注意事项** 1. **字节序处理** - 使用 `qToBigEndian()`/`qFromBigEndian()` 确保跨平台兼容性 2. **大数据传输** - 单次发送数据不超过 TCP 窗口大小(通常 64KB) - 超大文件需分片传输 3. **超时机制** - 添加 `waitForBytesWritten()` 防止入阻塞 > 完整实现可参考 Qt 官方文档:[QTcpSocket Class](https://doc.qt.io/qt-5/qtcpsocket.html)[^1],[QJsonDocument Usage](https://doc.qt.io/qt-5/qjsondocument.html)[^3]
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值