Qt는,

2016-08-25 17 views
1

내가 QTcpServer 및 QTcpSocket를 사용하여 클라이언트/서버 기반 Qt는 응용 프로그램을 스트리밍 여러 데이터 클라이언트에서 서버 유형 + 데이터 전송, 나는 연결을하고 사이에 앞뒤로 일부 데이터를 보낼 관리 클라이언트 및 서버. 클라이언트는 서버 (문자열, INT, 파일 및 실시간 오디오 스트림)에 많은 종류의 데이터를 전송하고 내 서버에 있기 때문에 하나의 데이터 입력 SLOT (readyRead()) impliment :Qt는,

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; 
    } 
};