2016-08-25 30 views
1

をストリーミングサーバー+データへのクライアントから複数のデータ型を送信する、私は接続を行うとの間で前後にいくつかのデータを送信するために管理クライアントとサーバー。 クライアントは、サーバ(文字列、int型、ファイルやリアルタイムオーディオストリーム)へのデータの多くの種類を送信し、私のサーバーは、単一のデータ入力SLOT(readyReadを())impliment以来:Qtは、私がQTcpServerとQTcpSocketを使用して<strong>クライアント/サーバ</strong>ベース<strong>のQt</strong>アプリケーションを、持っている

connect(socket, SIGNAL(readyRead()),this, SLOT(readyRead())); 

私はドン」この受信したすべてのデータを区別して、サーバー内の適切な機能をそれぞれ呼び出す方法を知っています。

Example (in the server): 
- if I receive string  => call function showData(QString data); 
- if I receive file   => call function saveFile(QFile file); 
- if I receive audio stream => play audio stream 
- ... 

SERVER:CLIENT

void Server::newClientConnection() 
{ 
    QTcpSocket *socket = server->nextPendingConnection(); 

    connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); 
    //... 
} 

void Server::readyRead() 
{ 
    QTcpSocket *clientSocket = qobject_cast<QTcpSocket *>(sender()); 
    if (clientSocket == 0) { 
     return; 
    } 

    QDataStream in(clientSocket); 

    if (sizeMessageClient == 0) 
    { 
     if (clientSocket->bytesAvailable() < (int)sizeof(quint16)){ 
      return; 
     } 
     in >> sizeMessageClient; 
    } 

    if (clientSocket->bytesAvailable() < sizeMessageClient) { 
     return; 
    } 

    sizeMessageClient = 0; 

    in >> data; 
/* 
    I don't know the type of the received data !! 

    - if I receive string  => call function showData(QString data); 
    - if I receive file   => call function saveFile(QFile file); 
    - if I receive audio stream => play audio stream 
    - ... 
*/ 

} 

:私は完全なソリューションを捜しているわけではない

Client::Client() 
{ 
    socket = new QTcpSocket(this); 
    connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); 

    sizeMessageServer = 0; 
} 


void Client::readyRead() 
{ 
    QDataStream in(socket); 
    if (sizeMessageServer == 0) 
    { 
     if (socket->bytesAvailable() < (int)sizeof(quint16)) { 
      return; 
     } 

     in >> sizeMessageServer; 
    } 

    if (socket->bytesAvailable() < sizeMessageServer) { 
     return; 
    } 

    int messageReceived; 
    in >> messageReceived; 
    messageReceived = static_cast<int>(messageReceived); 

    sizeMessageServer = 0; 

    switch(messageReceived) 
    { 
     case 1: 
      qDebug() << "send a File"; 
      sendFile(); 
      break; 
     case 2: 
      qDebug() << "send a string data"; 
      sendStringData(); 
      break; 
     case 3: 
      qDebug() << "stream audio to the server"; 
      streamAudioToServer(); 
      break; 
     case n: 
     // ...  
    } 
} 

、私が探していますすべてが正しい方向にいくつかのガイダンスです。

+2

あなたが発明する(または既存の使用)を使用すると、送信データの種類を伝えることができます*プロトコル*をする必要があるように思え。 –

+0

私はどのようにこれが起こることができるかの例をネット上で見つけることができません。 –

+2

最低でも、タイプと値をメッセージにパッケージ化し、タイプの受信側のスイッチでパッケージ化することができます。 –

答えて

2

Qt 5.7では、プロトコルの実装がQDataStreamを完全に活用していません。それは今見えるかもしれません - それは非常に簡単かもしれません。

最初に、私たちが知っているの要求を定義してみましょう:また、トランザクションRAIIヘルパーを持っていると便利だろう

enum class Req : quint32 { 
    Unknown, String, File 
}; 
Q_DECLARE_METATYPE(Req) 
QDataStream & operator<<(QDataStream & ds, Req req) { 
    return ds << (quint32)req; 
} 
QDataStream & operator>>(QDataStream & ds, Req & req) { 
    quint32 val; 
    ds >> val; 
    if (ds.status() == QDataStream::Ok) 
     req = Req(val); 
    return ds; 
} 

struct Transaction { 
    QDataStream & stream; 
    Transaction(QDataStream & stream) : stream{stream} { 
     stream.startTransaction(); 
    } 
    ~Transaction() { 
     stream.commitTransaction(); 
    } 
    bool ok() { 
     return stream.status() == QDataStream::Ok; 
    } 
}; 

クライアントはサーバーから要求を受け取り、データで返信する必要があることを知らせます。クライアントを使用するコードは、これらの信号に反応し、一致するスロットを呼び出して応答します。例えば。

void clientUser(Client & client) { 
    QObject::connect(&client, &Client::needString, &client, [&]{ 
    client.sendString(QStringLiteral{"You got string!"}); 
    }); 

そして:

class Client : public QObject { 
    Q_OBJECT 
    QIODevice & m_dev; 
    QDataStream m_str{&m_dev}; 
    void onReadyRead() { 
     Transaction tr{m_str}; 
     Req req; 
     m_str >> req; 
     if (!tr.ok()) return; 
     if (req == Req::String) 
      emit needString(); 
     else if (req == Req::File) { 
      QString fileName; 
      m_str >> fileName; 
      if (!tr.ok()) return; 
      emit needFile(fileName); 
     } 
     else emit unknownRequest(req); 
    } 
public: 
    Client(QIODevice & dev) : m_dev{dev} { 
     connect(&m_dev, &QIODevice::readyRead, this, &Client::onReadyRead); 
    } 
    Q_SIGNAL void unknownRequest(Req); 
    Q_SIGNAL void needString(); 
    Q_SIGNAL void needFile(const QString & fileName); 
    Q_SLOT void sendString(const QString & str) { 
     m_str << Req::String << str; 
    } 
    Q_SLOT void sendFile(const QString & fileName, const QByteArray & data) { 
     m_str << Req::File << fileName << data; 
    } 
}; 

サーバーは非常に似ています。そのユーザーは、requestスロットを介してクライアントに要求を送信します。サーバはバッククライアントから聞くと、それはhas信号を通してそれを示しています

class Server : public QObject { 
    Q_OBJECT 
    QIODevice & m_dev; 
    QDataStream m_str{&m_dev}; 
    void onReadyRead() { 
     Transaction tr{m_str}; 
     Req req; 
     m_str >> req; 
     if (!tr.ok()) return; 
     if (req == Req::String) { 
      QString str; 
      m_str >> str; 
      if (!tr.ok()) return; 
      emit hasString(str); 
     } 
     else if (req == Req::File) { 
      QString fileName; 
      QByteArray data; 
      m_str >> fileName >> data; 
      if (!tr.ok()) return; 
      emit hasFile(fileName, data); 
     } 
     else emit hasUnknownRequest(req); 
    } 
public: 
    Server(QIODevice & dev) : m_dev{dev} { 
     connect(&m_dev, &QIODevice::readyRead, this, &Server::onReadyRead); 
    } 
    Q_SIGNAL void hasUnknownRequest(Req); 
    Q_SIGNAL void hasString(const QString &); 
    Q_SIGNAL void hasFile(const QString & name, const QByteArray &); 
    Q_SLOT void requestString() { 
     m_str << Req::String; 
    } 
    Q_SLOT void requestFile(const QString & name) { 
     m_str << Req::File << name; 
    } 
}; 
関連する問題