通过网络发送的结构化数据[关闭](Sending structured data over a ne

2019-10-20 02:58发布

我在网络编程初学者一个,那么,对不起,如果我的问题,可能会出现一个小明显。

我试图从Qt应用程序发送一些数据,这将对其进行处理并传回了一些答案Python的服务器。

这让我在发送数据的方法QTcpSocket类有:

// ...
write(const QByteArray &)
write(const char *)
// ...

我的应用程序将管理:认证,发送和接收像一些配合物的数据struct和文件。

我已经对这种情况的许多问题:

  1. 上面提到足够的方法来发送配合物数据,以及如何?
  2. 如何处理在服务器端(与Python)的数据类型?
  3. 你觉得我应该使用其他protocole像HTTP(与QNetworkAccessManager类)?

Answer 1:

试图回答您的问题:

上面提到足够的方法来发送配合物数据,以及如何?

嗯,是的,发送原始字节数组是最低级别的格式。 但是,你需要的东西 ,可以让你唯一从复杂的数据的字节数组,并从字节数组回到你的复杂的数据。

这个过程被称为以不同的方式,编码,序列化,编组....但一般来说它只是意味着对于复杂结构编码成字节或字符序列创建系统

有很多,你可以选择: ASN.1 , JSON , XML , 谷歌的协议缓冲区或MIME ....

你甚至可以设计自己的(例如一个简单的模式是用TLV(标签长度值),其中标签是类型和值的标识可以是基本类型[你必须定义每个类型的表示是你考虑基本]或再次一个或多个TLV),长度表示多少字节/字符用于编码值。

什么选择在很大程度上取决于在那里你编码(语言/平台),并在那里你解码(语言/平台)和你的速度,带宽使用,运输,邮件是否应检查......等的要求

如果你正在处理异质架构,您可能需要考虑字节序 。

最后,应该用于编码的格式(即,复杂的结构如何表示为行字节序列)和库(或用于解码的库)之间进行区分。 有时他们会被联系在一起,有时相同的格式,你将有图书馆使用的选择。

如何处理在服务器端(与Python)的数据类型?

所以,在这里,你有一个要求......如果你要为外部提供的格式,你必须确保它能够解码它一个Python库。

如果你去一个土生土长的解决方案,事情你应该定义一个是你的复杂的C ++结构作为Python的结构表达。

另一种可能性是在C ++中做的一切,并为服务器蟒侧使用的系统中的一个在C ++创建蟒扩展(例如升压-蟒或痛饮 ....)

你觉得我应该使用其他协议,如HTTP(与QNetworkAccessManager类)?

这取决于你试图做什么。 目前被广泛使用,你可以在不同的语言和不同的架构使用的HTTP库。

你仍然需要解决决定您的信息的格式问题(虽然HTTP有一些定义的做法)。

此外HTTP显然是偏重客户端与服务器的通信,与总是由客户端发起的行动。

事情变得复杂(或更少的广泛支持)是服务器需要启动通信或需要发送自发信息的一个一个的时候。



Answer 2:

我不认为这是应该有所区别的语言数据结构类型,但它更多的是你发送过来的数据。 需要注意的是,不同的语言可能有不同的语言结构等。 这仅仅是非常低级别的细节。 更重要的是,你送什么。

你可以看看下面的例子中,序列化/反序列化的工作方式与QtCore JSON格式。 那么还将支持JSON在Python很好的json模块,所以你必须在服务器端没有问题反序列化:

JSON保存游戏实例

这基本上是会给你在客户端的一些提示的重要组成部分。 不要迷失在保存到一个文件中。 它基本上是写入文件,你会通过在网络上发送替换原始字节:

void Game::write(QJsonObject &json) const
{
    QJsonObject playerObject;
    mPlayer.write(playerObject);
    json["player"] = playerObject;

    QJsonArray levelArray;
    foreach (const Level level, mLevels) {
        QJsonObject levelObject;
        level.write(levelObject);
        levelArray.append(levelObject);
    }
    json["levels"] = levelArray;
}

...然后你会做在服务器端这样的事情,再次而不是从文件中读取数据,你会从网络上阅读,但不是一个大问题,因为已IO。

import json
json_data=open(file_directory).read()

data = json.loads(json_data)
pprint(data)

你可以使用原始协议来设计自己的,或只是使用的延伸。 我建议去与一些标准,如HTTP(TCP / UDP)。 然后,你只需要定义JSON格式为您自己的数据,而不是处理所有的休息,比如单向或双向通信,针对重放攻击,时间戳,数据大小等事务标识符。

这将允许您真正专注于为你重要的东西。 一旦你定义了你自己的JSON格式,你可以看着QtNetwork模块 ,你想送岗位,GET,PUT和DELETE请求。

你可能会与紧密合作QNetworkManager , QNetworkReply类,等等。 在这里,你可以找到Qt中有QtCore的JSON的简单引擎收录功能的简单客户端的实现:

#include <QSslError>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QTcpSocket>

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QFile>
#include <QScopedPointer>
#include <QTextStream>
#include <QStringList>
#include <QCoreApplication>

#include <QDebug>

int main(int argc, char **argv)
{
    QCoreApplication application{argc, argv};
    application.setOrganizationName(R"("CutePaste")");
    application.setApplicationName(R"("CutePaste Desktop Console Frontend")");

    QTextStream standardOutputStream{stdout};
    QFile dataFile;
    QString firstArgument{QCoreApplication::arguments().size() < 2 ? QString() : QCoreApplication::arguments().at(1)};
    if (!firstArgument.isEmpty()) {
        dataFile.setFileName(firstArgument);
        dataFile.open(QIODevice::ReadOnly);
    } else {
        dataFile.open(stdin, QIODevice::ReadOnly);
    }

    QByteArray pasteTextByteArray{dataFile.readAll()};

    QJsonObject requestJsonObject;
    requestJsonObject.insert(QStringLiteral("data"), QString::fromUtf8(pasteTextByteArray));
    requestJsonObject.insert(QStringLiteral("language"), QStringLiteral("text"));

    QJsonDocument requestJsonDocument{requestJsonObject};

    QString baseUrlString{QStringLiteral(R"("http://pastebin.kde.org")")};

    QNetworkRequest networkRequest;
    networkRequest.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
    networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, R"("application/json")");
    networkRequest.setUrl(QUrl(baseUrlString + R"("/api/json/create")"));

    QNetworkAccessManager networkAccessManager;
    QScopedPointer<QNetworkReply> networkReplyScopedPointer(networkAccessManager.post(networkRequest, requestJsonDocument.toJson()));
    QObject::connect(networkReplyScopedPointer.data(), &QNetworkReply::finished, [&] {

        QJsonParseError jsonParseError;
        QByteArray replyJsonByteArray{networkReplyScopedPointer->readAll()};
        QJsonDocument replyJsonDocument{QJsonDocument::fromJson(replyJsonByteArray, &jsonParseError)};
        if (jsonParseError.error != QJsonParseError::NoError) {
            qDebug() << R"("The json network reply is not valid json:")" << jsonParseError.errorString();
            QCoreApplication::quit();
        }

        if (!replyJsonDocument.isObject()) {
            qDebug() << R"("The json network reply is not an object")";
            QCoreApplication::quit();
        }

        QJsonObject replyJsonObject{replyJsonDocument.object()};
        QJsonValue resultValue{replyJsonObject.value(QStringLiteral("result"))};

        if (!resultValue.isObject()) {
            qDebug() << R"("The json network reply does not contain an object for the "result" key")";
            QCoreApplication::quit();
        }

        QJsonValue identifierValue{resultValue.toObject().value(QStringLiteral("id"))};

        if (!identifierValue.isString()) {
            qDebug() << R"("The json network reply does not contain a string for the "id" key")";
            QCoreApplication::quit();
        }

        endl(standardOutputStream << baseUrlString << '/' << identifierValue.toString());

        QCoreApplication::quit();
    });

    QObject::connect(networkReplyScopedPointer.data(), static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), [&](QNetworkReply::NetworkError networkReplyError) {
        if (networkReplyError != QNetworkReply::NoError)
            endl(standardOutputStream << networkReplyScopedPointer->errorString());
    });

    QObject::connect(networkReplyScopedPointer.data(), &QNetworkReply::sslErrors, [&](QList<QSslError> networkReplySslErrors) {
        if (!networkReplySslErrors.isEmpty()) {
            for (const auto &networkReplySslError : networkReplySslErrors)
                endl(standardOutputStream << networkReplySslError.errorString());
        }
    });

    int returnValue{application.exec()};

    dataFile.close();
    if (dataFile.error() != QFileDevice::NoError)
        endl(standardOutputStream << dataFile.errorString());

    return returnValue;
}

该JSON被定义如下:

http://sayakb.github.io/sticky-notes/pages/api/

可以肯定,这是不这样做,例如,如果你需要的效率,你可能看起来像成二进制格式的唯一途径capnproto 。



文章来源: Sending structured data over a network [closed]