如何使用 QTcpSocket 获取 Protobuf 发送的数据 [重复]

Posted

技术标签:

【中文标题】如何使用 QTcpSocket 获取 Protobuf 发送的数据 [重复]【英文标题】:How to get datas send by Protobuf with a QTcpSocket [duplicate] 【发布时间】:2019-07-31 07:54:27 【问题描述】:

我是 protobuf 和 QTcpServer/Socket 的新手,我想读取我的客户端发送的 .proto 数据,但是当我读取数据时,QString done 是空的

现在,我只想在我的客户端连接时发送一条说“你好”的消息。 QTcpSocket::readAll 返回的QByteArray 不为空,但使用字节创建的QString 为空。

这是我的.proto 超基本的一个:

syntax = "proto3";

package protobuf;
message Message

    string content = 2;

编写函数:

// When i'm connecting to the server i create a PlayerManager and i call this function with message = "hello"
void Server::sendMessageToPlayer(const PlayerManager& playerManager, const QString& message)

    auto messageProto = new protobuf::Message;
    messageProto->set_content(message.toStdString());

    playerManager.socketManager()->sendData(*messageProto);


// I serialize the protobuf
template <typename protobufType>
void sendData(const protobufType& protobuf)

    std::string dataToSend;
    if (!protobuf.SerializeToString(&dataToSend))
    
        // This never pass -> the protobuf is well serialize 
        qDebug() << "The protobuf send cannot be serialized, please, make sure that you used protobufs correctly";
    

    // Before i write it
    write(dataToSend);


void SocketManager::write(const std::string& data)

    // I tried this but it's not working either
    // QTextCodec* codec     = QTextCodec::codecForName("CP1251");
    // QString     codecData = codec->toUnicode(data.c_str());

    QByteArray  block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_10);

    out << data.c_str();
    _tcpSocket->write(block);
    qDebug() << block;

读取函数:

void SocketManager::read()

    QByteArray bytes = _tcpSocket->readAll();
    qDebug() << bytes;

    // Doesn't work either
    // QTextCodec* codec = QTextCodec::codecForName("CP1251");
    // QString     data  = codec->toUnicode(bytes);
    QString     data(bytes);
    qDebug() << data;

    emitMessageType(data.toStdString());


void SocketManager::emitMessageType(const std::string& data)

    // Protobufs can parse an empty string (and so, emit signal), to avoid that, the function will tell you if data
    // are empty, then return
    if (data.empty())
    
        qDebug() << "Datas are empty";
        return;
    

    protobuf::Message message;
    if (message.ParseFromString(data))
    
        emit messageProtoReceived(message);
        return;
    

    qDebug() << "The data send cannot be translate, please, make sure that you used protobufs correctly";

所以,我希望我的客户在连接时收到“hello”,但我的调试是:

服务器端:

"\x00\x00\x00\b\x12\x05hello\x00"

客户端

"\x00\x00\x00\b\x12\x05hello\x00"
""
Datas are empty

当我使用QTextCodec(代码的注释行)时,调试是:

服务器端:

"\x00\x00\x00\x0E\x00\x12\x00\x05\x00h\x00""e\x00l\x00l\x00o"

客户端

"\x00\x00\x00\x0E\x00\x12\x00\x05\x00h\x00""e\x00l\x00l\x00o"
"\u0000\u0000\u0000\u000E\u0000\u0012\u0000\u0005\u0000h\u0000e\u0000l\u0000l\u0000o"
The data send cannot be translate, please, make sure that you used protobufs correctly

所以QByteArea被解析了,但是protobuf没有成功解析给定的字符串。

感谢您的阅读,希望您能帮助我

【问题讨论】:

out &lt;&lt; data.c_str() 内部写入函数可能会首先丢弃\0。尝试转换为QByteArray,如下所述:***.com/questions/10767760/… 以确保通过套接字发送整个字符串。 QByteArray block(data.c_str(), data.length()); QDataStream out(&amp;block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_5_10); _tcpSocket-&gt;write(block); 这是有效的!你能回答吗,我会把它标记为已接受 【参考方案1】:

不确定是否是这种情况,但文档说QString 的默认构造函数采用QByteArray

使用 fromUtf8() 将给定的字节数组转换为 Unicode。在第一个 0 字符处停止复制,否则复制整个字节数组。

因此,您可能在转换过程中遇到了一些麻烦。

作为替代方案,您可以尝试ParseFromArray 方法,而不是将QByteArray 转换为std::string

const auto byteArray = _tcpSocket->readAll();
protobuf::Message message;
if (!message.ParseFromArray(byteArray.data(), byteArray.size())) 
    qDebug() << "Failed to parse person.pb.";

【讨论】:

这是有效的,但只有当我按照@Zaiborg 告诉我的去做时。它也适用于 ParseFromString :)。不管怎么说,还是要谢谢你 !但我还有另一个问题,你似乎知道 protobuf。为了更清楚我的代码,我没有说我尝试在我的emitMessageType 函数中解析不同类型的.proto。首先要解析的是 protobuf::Player,它要求一个 int AND 一个字符串。但是 protobuf::Player 使用 protobuf::Message 序列化的字符串成功解析,这很麻烦 抱歉@Ephesiel,但我不明白您的问题,也许您可​​以通过 protobuf 模型或代码本身的小示例在您的问题中提供更新。 抱歉,很难用一点评论来解释,这是我提出的另一个问题的链接-> link【参考方案2】:

out &lt;&lt; data.c_str()SocketManager::write 中可能会首先丢弃\0。尝试按照Correct way to losslessly convert to and from std::string and QByteArray 中的说明转换为QByteArray,以确保发送整个字符串。

【讨论】:

以上是关于如何使用 QTcpSocket 获取 Protobuf 发送的数据 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

将ProtoA导入protoB

如何使用 QTcpSocket 读取超过 8192 字节?

如何使用qtcpsocket一次写一个字符串?

如何使用 QTcpSocket 监听 qt 中的特定端口? [复制]

QTcpSocket如何返回QString

如何在不同的线程中执行 QTcpSocket?