I understand with Tcp the protocol in Qt. There is a server, it sends a message to the client.
void Server::sendToClientMessage() { if (socket != NULL) { // Заранее размер блока неизвестен, мы не можем записать данные сразу в сокет, // так как размер блока должен быть выслан в первую очередь QByteArray arrBlock; QDataStream out(&arrBlock, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_5_7); // Записываем все данные блока, размер 0 out << quint16(0); out << QTime::currentTime() << ui->lineEdit_message->text(); // Вывод вашего сообщения в историю сообщений ui->textEdit_allMessage->append(QTime::currentTime().toString() + " - Ваше сообщение: " + ui->lineEdit_message->text()); // Перемещение указателя на начало блока out.device()->seek(0); // Вычисление размера блока arrSize уменьшенный на sizeof(quint16) // запись в поток out с текущей позиции, которая уже перемещена в начало блока out << quint16(arrBlock.size() - sizeof(quint16)); // Созданный блок записывается в сокет socket->write(arrBlock); ui->lineEdit_message->clear(); } else { return; } } He also sends the picture to the client by pushButton
void Server::transferImage() { QBuffer buffer; QImageWriter writer(&buffer, "jpg"); writer.write(imageJPEG); QByteArray barr; QDataStream stream(&barr, QIODevice::WriteOnly); stream.setVersion(QDataStream::Qt_5_7); stream << (quint32)buffer.size(); barr.append(buffer.data()); socket->write(barr); } How does the client side determine what comes up? message or picture? There are 2 connections
// Передача сообщения клиенту connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); // Передача картинки клиенту connect(socket, SIGNAL(readyRead()), this, SLOT(receivingImage())); Now they work out 2 methods and this is not correct. If we transmit a picture, he tries to display the message too, although we did not transmit it, and vice versa. Because of this, none of the methods work. If you comment out one of the connections and the corresponding slot, then all is normal. Ie either a message or a picture. It would be possible to stuff it into one method and inside it can already be disassembled, but how can you define a picture inside the method or just a message?
Server Connection Method
void Client::connectedToServer() { // Если клиент уже подключен if(socket != NULL) { // Отключить клиента клиента disconnectFromServer(); } else { socket = new QTcpSocket(this); // Подключение к серверу socket->connectToHost(ui->lineEdit_ipAddress->text(),ui->spinBox_port->value()); // оповестить пользователя что он подключён connect(socket, SIGNAL(connected()), this, SLOT(slotConnected())); //connect(sock) // Возможные ошибки при подключении connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotError(QAbstractSocket::SocketError))); // Передача сообщения клиенту connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); // Передача картинки клиенту connect(socket, SIGNAL(readyRead()), this, SLOT(receivingImage())); } } Receiving a message
void Client::slotReadyRead() { // Считывание в двоичный поток данных, объект класса socket унасследованный от QIODevice QDataStream in(socket); // Так как формат постоянно изменяется, и в разных версиях он может работать по разному. // Установка формата обмена данных на версию Qt 5.7. in.setVersion(QDataStream::Qt_5_7); // Не все высланные клиентом данные могут прийти одновременно. // Сервер должен уметь получать, как весь блок целиком, так и только часть блока, // а так же и все блоки сразу. for (;;) { // Размер блока заранее неизвестен, сравниваем с нулём. if (nextBlockSize == 0) { // Если пришло меньше 2-х байт, ждём пока будет 2 байта. // Первые 2 байта это размер блока if (socket->bytesAvailable() < (int)sizeof(quint16)) { break; } // Блок получен целиком. Считываем размер блока (2 байта) in >> nextBlockSize; } // Ждём пока блок придёт полностью if (socket->bytesAvailable() < nextBlockSize) { break; } // Вот тут можно было бы определять картинка здесь или сообщение, но как? // Определяем дату и строку, они в сообщении сервера QTime time; QString str; // Считывание данных из потока в переменные in >> time >> str; ui->textEdit_allMessage->append(time.toString() + " - Сообщение от сервера: " + str); // Каждый раз обнуляем блок, для принятия следующего nextBlockSize = 0; } } Receiving pictures
void Client::receivingImage() { if (nextBlockSize == 0) { QDataStream stream(socket); if (socket->bytesAvailable() < sizeof(quint32)) return; stream >> nextBlockSize; } if (nextBlockSize > socket->bytesAvailable()) return; QByteArray barr = socket->read(nextBlockSize); QBuffer buffer(&barr); buffer.open(QIODevice::ReadOnly); QImageReader reader(&buffer, "jpg"); receivingImageJPG = reader.read(); if (!receivingImageJPG.isNull()) { ui->label_reciveImageJPG->setPixmap(QPixmap::fromImage(receivingImageJPG).scaled(ui->label_reciveImageJPG->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); nextBlockSize = 0; } else { ui->label_reciveImageJPG->setText("Возникла ошибка при передачи картинки."); } } Here's something like this is needed. But there is a hard limit if more than 10 kilobytes arrive, we believe that this is a picture and is displayed. If less, then the message. How to recognize in advance what is stored in the QDataStream message or picture?
void Client::slotReadyRead() { // Считывание в двоичный поток данных, объект класса socket унасследованный от QIODevice QDataStream in(socket); // Так как формат постоянно изменяется, и в разных версиях он может работать по разному. // Установка формата обмена данных на версию Qt 5.7. in.setVersion(QDataStream::Qt_5_7); // Не все высланные клиентом данные могут прийти одновременно. // Сервер должен уметь получать, как весь блок целиком, так и только часть блока, // а так же и все блоки сразу. for (;;) { // Размер блока заранее неизвестен, сравниваем с нулём. if (nextBlockSize == 0) { // Если пришло меньше 2-х байт, ждём пока будет 2 байта. // Первые 2 байта это размер блока if (socket->bytesAvailable() < (int)sizeof(quint64)) { break; } // Блок получен целиком. Считываем размер блока (2 байта) in >> nextBlockSize; } // Ждём пока блок придёт полностью if (socket->bytesAvailable() < nextBlockSize) { break; } if (nextBlockSize < 10000) { // Определяем дату и строку, они в сообщении сервера QTime time; QString str; // Считывание данных из потока в переменные in >> time >> str; ui->textEdit_allMessage->append(time.toString() + " - Сообщение от сервера: " + str); } else { QByteArray barr = socket->read(nextBlockSize); QBuffer buffer(&barr); buffer.open(QIODevice::ReadOnly); QImageReader reader(&buffer, "jpg"); receivingImageJPG = reader.read(); if (!receivingImageJPG.isNull()) { ui->label_reciveImageJPG->setPixmap(QPixmap::fromImage(receivingImageJPG).scaled(ui->label_reciveImageJPG->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); } else { ui->label_reciveImageJPG->setText("Возникла ошибка при передачи картинки."); } } // Каждый раз обнуляем блок, для принятия следующего nextBlockSize = 0; } }