0 / 0 / 0
Регистрация: 02.06.2015
Сообщений: 22
1

Сетевой обмен через QTcpSocket's

04.06.2015, 02:17. Показов 8604. Ответов 15
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
И снова доброй ночи

В общем-то на этот раз все работает, однако работает как написано, а не как задумано

Проблемное место в передаче данных между двумя клиентами. Вроде бы приложение данные отправляет, но они либо не доходят, либо я что-то упускаю и не читаю их (ну или третий вариант, однако мне других причин в голову не приходит).

Проверяю я это запуском двух одинаковых прог на одной машине (адрес вбиваю, соответственно, 127.0.0.1. Порт сервер слушает либо 9100-ый, либо если такой занят, то 9110-ый).

Быть может подскажет кто?

Код проблемного блока + архив с всем проектом прикладываю.

tcpclient.h

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#ifndef TCPClient_H
#define TCPClient_H
 
#include "include.h"
 
class MyClient : public QDialog
{
    Q_OBJECT
public:
    static const quint8 MESSAGE = 1;
    static const quint8 UNSECURED_CONNECTION = 2;
    static const quint8 SECURITY_CHECK = 3;
    MyClient(QWidget *parent);
    bool isConnectionSecured()
    {
        return ConnectionSecurityStatus;
    }
private:
    QTcpSocket *_socket;    // Сокет
    QTcpServer *_server;
    quint16 _blockSize;     // Текущий размер блока данных
    bool ConnectionSecurityStatus;  // TRUE - ключи для шифрования созданы и проверены
                                    // FALSE - ключи не были сгенерированы или проверка
                                    // шифрования заданой строки выявила ошибку
    bool isConnectionExist = 0; // По задумке чат может быть только 1 на 1, т.о. если
                                // isConnectionExist = 1, то при запросе на соединение
                                // отправится сообщение о занятости юзверя
    uint nPort = 9100;
    // Отправляем сообщение клиенту отсюда
    void SendToClient (QTcpSocket *socket, const QString *str);
private slots:
// Слоты "клиента":
    void SocketConnected();
    void SocketDisconnected();
    // Cигнал readyRead вызывается, когда сокет получает пакет
    // (который может быть лишь частью отправленых данных) байтов
    void SocketReadyRead();
    void SocketDisplayError(int socketError);
// Слоты "сервера":
    // Создаем соединения тут
    void ServerNewConnection();
    // Показ ошибки при соединении
    void ShowServerError(int serverError);
public slots:
    // Слот Connect получает сигнал (с данными) от Dialog для создания подключения
    void Connect(QHostAddress IP, quint16 Port);
    // Сюда приходит зашифрованное сообщение для отправки
    void SendMessageOut (const QString *message);
signals:
    // Сигнал для MainWindow c зашифрованным сообщением
    void NewMessage(const QString *message);
    // Сигнал установки соединения (закрывает Dialog'овое окно)
    void ConnectionValid();
};
 
#endif // TCPClient_H

tcpclient.cpp

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include "tcpClient.h"
 
MyClient::MyClient(QWidget *parent):
    QDialog(parent)
{
    // Создаем сокет
    _socket = new QTcpSocket(this);
    // Создаем сервер
    _server = new QTcpServer(this);
 
    // Проверка сокета
/*    if(!_socket->isValid())
    {
        QMessageBox::critical(0, "Socket Error",
                              "Unable to create a socket: "
                              + _socket->errorString());
        _socket->abort();
        return;
    }*/
    // Проверка сервера
    if(!_server->listen(QHostAddress::Any, nPort))
    {
        if(!_server->listen(QHostAddress::Any, nPort+10))
        {
            QMessageBox::critical(0, "Server Error",
                              "Unable to start the server: "
                              + _server->errorString());
            _server->close();
            return;
        }
    }
    // Подключаем сигналы "сервера"
    connect(_server, SIGNAL(newConnection()), this, SLOT(ServerNewConnection()));
//    connect(_server, SIGNAL(acceptError(QAbstractSocket::SocketError)),
//                  this, SLOT(ShowServerError(int)));
    // Подключаем сигналы "клиента"
    connect(_socket, SIGNAL(readyRead()), this, SLOT(SocketReadyRead()));
    connect(_socket, SIGNAL(connected()), this, SLOT(SocketConnected()));
    connect(_socket, SIGNAL(disconnected()), this, SLOT(SocketDisconnected()));
//    connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)),this,
//                        SLOT(SocketDisplayError(int)));
}
 
void MyClient::Connect(QHostAddress IP, quint16 Port)
{
    _socket->connectToHost(IP, Port);
    if(_socket->isValid())
    {
        isConnectionExist = 1;
        emit ConnectionValid();
    }
    else
    {
        QMessageBox::critical(0, "Socket Error",
                              "Unable to create a socket: "
                              + _socket->errorString());
        _socket->abort();
        return;
    }
}
 
void MyClient::ServerNewConnection()
{
    QTcpSocket *ClientSocket = _server->nextPendingConnection();
 
    // Если одно соединение уже существует, то вежливо извиняемся и обрываем соединение
    if(isConnectionExist)
    {
        QString Apologizing_Message = "This user is alredy chating with someone(";
        SendToClient(ClientSocket, &Apologizing_Message);
        ClientSocket->disconnectFromHost();
        return;
    }
    else
    {
        QString Message = "Connection established!";
        SendToClient(ClientSocket, &Message);
    }
    // Теперь _socket соединен с запрашивававшимм соединение
    _socket = ClientSocket;
    // Запоминаем, что соединение установлено
    isConnectionExist = 1;
}
 
void MyClient::SendToClient(QTcpSocket *socket, const QString *str)
{
    // Если вдруг мы считаем, что соединения нет
//    if(!isConnectionExist)
//        return;
 
    // Если считаем, что соединение не безопасно
    if(!ConnectionSecurityStatus)
    {
        // todo: Сигнал на новый обмен кодами шифрования
    }
 
    QByteArray *message;
    message = new QByteArray;
    QDataStream out(message, QIODevice::WriteOnly);
 
    out.setVersion(QDataStream::Qt_5_4);
 
    // Оставляем два пустых байта под размер сообщения, третий байт - код, показывающий
    // как сообщение будет обработано и в конец записываем само сообщение
    out << quint16(0) << quint8(MESSAGE) << str;
 
    // Возвращаемся на начало
    out.device()->seek(0);
 
    // И дописываем в оставленные пустыми два байта размер сообщение
    // (размер только самой строки)
    out << quint16(message->size() - sizeof(quint16));
 
    // Наконец отправляем сообщение
    socket->write(message->toStdString().c_str());
    emit socket->readyRead();
    delete message;
}
 
void MyClient::SocketConnected()
{
// После подключения следует отправить запрос на авторизацию
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
 
    out.setVersion(QDataStream::Qt_5_4);
 
//резервируем 2 байта для размера блока. Класс MyClient используется в реализации сервера, но тут используем статические члены этого класса - константы команд
//третий байт - команда
    out << (quint16)0 << (quint8)MyClient::UNSECURED_CONNECTION;
 
//возваращаемся в начало
    out.device()->seek(0);
//вписываем размер блока на зарезервированное место
    out << (quint16)(block.size() - sizeof(quint16));
    if(_socket->write(block) == -1)
    {
        QMessageBox::critical(this, "Error",
                              "Error while writing in socket");
    }
}
 
void MyClient::SocketDisconnected()
{
    isConnectionExist = 0;
    _socket->disconnectFromHost();
    _server->close();
}
 
void MyClient::SocketDisplayError(int socketError)
{
    QMessageBox::critical(0, "Socket Error!", tr("Code: %1").arg(socketError));
}
 
void MyClient::ShowServerError(int serverError)
{
    QMessageBox::critical(0, "Server Error!", tr("Code: %1").arg(serverError));
}
 
void MyClient::SendMessageOut (const QString *message)
{
   emit SendToClient(_socket, message);
}
 
void MyClient::SocketReadyRead()
{
//тут обрабатываются данные от сервера
    QDataStream in(_socket);
//если считываем новый блок первые 2 байта это его размер
 
    if (_blockSize == 0) {
//если пришло меньше 2 байт ждем пока будет 2 байта
        if (_socket->bytesAvailable() < (int)sizeof(quint16))
            return;
//считываем размер (2 байта)
        in >> _blockSize;
    }
//ждем пока блок придет полностью
    if (_socket->bytesAvailable() < _blockSize)
        return;
    else //можно принимать новый блок
        _blockSize = 0;
//3 байт - команда серверу
    quint8 command;
    in >> command;
 
    switch (command)
    {
//общее сообщение от сервера
        case MyClient::MESSAGE:
        {
//Скидываем сообщение на расшифровку
            QString message;
            in >> message;
            emit NewMessage(&message);
        }
        case MyClient::UNSECURED_CONNECTION:
        {
 
            // todo: Обработку команды сервера о незащищенном канале (т.е. обмен ключами)
        }
    }
}
Вложения
Тип файла: rar Encryptor_v0_1.rar (12.4 Кб, 24 просмотров)
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.06.2015, 02:17
Ответы с готовыми решениями:

Объектно-ориентированный сетевой обмен
Есть задача по реализации удаленного управления объектом. Существует ли что то более изящное чем...

Как создать беспроводное подключение между ПК, подключенного через сетевой кабель к модему, и ноутбуком, подключенным к этому же модему через Wi-fi?
На обоих машинах семерка. И как открыть в этой сети доступы к локальным дискам, на обоих машинах....

Обмен через порт
нужно написать две программки под UNIX, которые общались бы между собой через последовательный порт...

Обмен-валюта через ВебМани
как создать скрипты обмен-валюта через ВебМани? Моете подсказать, где может найти готовые скрипты....

15
161 / 126 / 30
Регистрация: 30.05.2015
Сообщений: 380
04.06.2015, 10:23 2
Как то странно написано всё, сложно дебажить.

я бы всё таки либо 2 приложения различных сделал (клиент отдельно, чат отдельно), либо при запуске выбор предоставить, клиентом хочется быть, или сервером.

Совсем уж в глубь лезть не хочеться, но что бросилось в глаза:

C++ (Qt)
1
2
3
4
5
6
void MyClient::ServerNewConnection()
{
    QTcpSocket *ClientSocket = _server->nextPendingConnection();
// ....
    _socket = ClientSocket;
}
не конектишь сигналы к вновь подключенному клиенту, соответственно "сервер" не знает о входящих сообщениях.
1
0 / 0 / 0
Регистрация: 02.06.2015
Сообщений: 22
04.06.2015, 13:21  [ТС] 3
Kurles, у меня еще в конструкторе MyClient написано вот это:

C++ (Qt)
1
2
3
4
5
6
7
    _socket = new QTcpSocket(this);
 
    ....
 
    connect(_socket, SIGNAL(readyRead()), this, SLOT(SocketReadyRead()));
    connect(_socket, SIGNAL(connected()), this, SLOT(SocketConnected()));
    connect(_socket, SIGNAL(disconnected()), this, SLOT(SocketDisconnected()));
Т.е. по идее при приравнивании _socket = ClientSocket; эти соединения должны остаться. Или нет?
0
161 / 126 / 30
Регистрация: 30.05.2015
Сообщений: 380
04.06.2015, 14:46 4
Цитата Сообщение от Nikita6000 Посмотреть сообщение
Т.е. по идее при приравнивании _socket = ClientSocket; эти соединения должны остаться. Или нет?
Нет, потому что в методе ServerNewConnection и конструкторе класса разные экземпляры QTcpSocket.
1
0 / 0 / 0
Регистрация: 02.06.2015
Сообщений: 22
04.06.2015, 15:04  [ТС] 5
Kurles, не совсем понимаю.

У меня есть единственный объект класса MyClient, приписанный как private-член класса MainWindow:
C++ (Qt)
1
MyClient *Client;
В конструкторе MainWindow я задаю два сигнала для связи с Client'ом:

C++ (Qt)
1
2
3
4
5
6
7
    // Отправляем зашифрованное сообщение собеседнику
    connect(Encryptor, SIGNAL(SendMessageToClient(const QString*)), Client,
                                        SLOT(SendMessageOut(const QString*)));
 
    // Decryptor получает сообщение от клиента
    connect(Client , SIGNAL(NewMessage(const QString*)), this ,
                                        SLOT(MessageReceived(const QString*)));
В классе MyClient есть два private объекта:

C++ (Qt)
1
2
QTcpSocket *_socket;   
    QTcpServer *_server;
По задумке через _socket должны происходить три действия: установка исходящего соединения, отправка данных и прием данных. _server же нужен только для слушания заданного порта. После того, как к нему постучались, он записывает соединение в _socket. Если же соединение уже есть, то происходит отправка извиняющегося сообщения и обрыв соединения:

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void MyClient::ServerNewConnection()
{
    QTcpSocket *ClientSocket = _server->nextPendingConnection();
 
    // Если одно соединение уже существует, то вежливо извиняемся и обрываем соединение
    if(isConnectionExist)
    {
        QString Apologizing_Message = "This user is alredy chating with someone(";
        SendToClient(ClientSocket, &Apologizing_Message);
        ClientSocket->disconnectFromHost();
        return;
    }
    else
    {
        QString Message = "Connection established!";
        SendToClient(ClientSocket, &Message);
    }
    // Теперь _socket соединен с запрашивавшим соединение
    _socket = ClientSocket;
 
 
/// Добавил по вашему совету, но ничего не изменилось.
    connect(_socket, SIGNAL(readyRead()), this, SLOT(SocketReadyRead()));
    connect(_socket, SIGNAL(connected()), this, SLOT(SocketConnected()));
    connect(_socket, SIGNAL(disconnected()), this, SLOT(SocketDisconnected()));
 
    // Запоминаем, что соединение установлено
    isConnectionExist = 1;
Вот как-то так. Сама концепция вообще осуществима? Или я чего-то не вижу/не знаю?
0
161 / 126 / 30
Регистрация: 30.05.2015
Сообщений: 380
04.06.2015, 15:47 6
Ну если идти твоим путём, то немного поменял бы логику.
1. ввод пользователем адреса/порта для подключения
2. попытка присоедениться через него к серверу.
3. дождаться результата.
4. при положительном результате - работаем с созданным соединением.
5. иначе - удаляем сокет (через deleteLater), обнуляем указатель.
6. стартуем сервер на порту, кот. ввёл пользователь на первом шаге.
7. не получилось - пишем сообщение, выход
8. получилось - ждём подключившегося.
9. есть соедниение - запоминает подключившийся сокет, конектим его сигналы с нашими и работаем с ним до отклчения, после отклчения клиента удаляем сокет, обнуляем указатель на него, и к 8 шагу переходим.
0
0 / 0 / 0
Регистрация: 02.06.2015
Сообщений: 22
04.06.2015, 16:03  [ТС] 7
Kurles, Собственно я пытаюсь сделать почти так же, только сервер у меня стартует одновременно с запуском проги (позже допишу выбор порта пользователем) и либо к нему приходит соединение и работа происходит через него, либо пользователь сам инициализирует соединение.

Прикол в том, что соединение вроде как устанавливается. По крайней мере вот этот код срабатывает:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
void MyClient::Connect(QHostAddress IP, quint16 Port)
{
    _socket->connectToHost(IP, Port);
    if(_socket->isValid())
    {
        isConnectionExist = 1;
        emit ConnectionValid(); // Это сигнал на закрытие окна Dialog
    }
else...
...
}
И брейкпоинт вот тут так-же срабатывает:

C++ (Qt)
1
2
3
4
5
6
7
8
9
void MyClient::SendToClient(QTcpSocket *socket, const QString *str)
{
    ...
 
// Наконец отправляем сообщение
    socket->write(message->toStdString().c_str());
    emit socket->readyRead(); // Вот этого тут изначально не было и я не уверен что оно тут должно быть
    delete message;
}
Но в другой запущенной проге не происходит чтения (информация не приходит)
0
161 / 126 / 30
Регистрация: 30.05.2015
Сообщений: 380
04.06.2015, 16:08 8
_socket->isValid() - не говорит о том, что ты подключился.
подключение надо отлавливать через сигнал void QAbstractSocket::connected(),
ошибки соединения через сигнал void QAbstractSocket::error(QAbstractSocket::SocketError socketError) и/или void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState).
1
0 / 0 / 0
Регистрация: 02.06.2015
Сообщений: 22
04.06.2015, 16:26  [ТС] 9
Kurles, хм, про IsValid спасибо.

сигнал connected у меня ловится, и даже вот этот if не срабатывает:
C++ (Qt)
1
2
3
4
5
6
7
8
9
void MyClient::SocketConnected()
{
...
    if(_socket->write(block) == -1)
    {
        QMessageBox::critical(this, "Error",
                              "Error while writing in socket");
    }
}
сигнал об ошибке у меня был закомментирован (были какие-то траблы). Исправил, обрабатывается. При попытке подключиться в рамках одного приложение он возвращает код 1 (The remote host closed the connection. Note that the client socket (i.e., this socket) will be closed after the remote close notification has been sent.).

При подключении одной проге к другой (сервера на портах 9100 и 9110 соответственно) ошибки нет (не ловится), сигнал connected() так-же обрабатывается, но данные уходят в неизвестном направлении.
0
161 / 126 / 30
Регистрация: 30.05.2015
Сообщений: 380
04.06.2015, 16:53 10
возможно где-то _socket внутири путаются, и ты пытаешься серверным сокетом читать клиентские данные. Перепиши, что бы сервер создавался только если не получилось вначале через сокет соединиться.
1
0 / 0 / 0
Регистрация: 02.06.2015
Сообщений: 22
04.06.2015, 17:49  [ТС] 11
Kurles, у меня только один _socket, не с чем ему вроде бы путаться.

На всякий все-таки проверил вот так: запустил три проги сразу. две первые заняли порты 9100 и 9110, третья соответственно напоролась на
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
if(!_server->listen(QHostAddress::Any, nPort))
    {
        if(!_server->listen(QHostAddress::Any, nPort+10))
        {
            QMessageBox::critical(0, "Server Error",
                              "Unable to start the server: "
                              + _server->errorString());
            _server->close();
            return;
        }
    }
И сервер не создался. Из неё попробовал подключиться к 127.0.0.1 и понаставил брейк-поинтов:

1) Сработал слот Connect:
C++ (Qt)
1
2
3
4
5
6
7
8
9
void MyClient::Connect(QHostAddress IP, quint16 Port)
{
    _socket->connectToHost(IP, Port);
    if(_socket->isValid())
    {
        isConnectionExist = 1;  // 
        emit ConnectionValid();
    }else{...}
}
Dialog отработал сигнал на закрытие окна с выбором IP и isConnectionExist теперь равен TRUE

По-хорошему от сервера должен был тут-же прийти ответ, но его нет.

2) При написании сообщения сработал слот:
C++ (Qt)
1
2
3
4
void MyClient::SendMessageOut (const QString *message)
{
   emit SendToClient(_socket, message);
}
3) В слоте SendToClient выполнилось следующее:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    QByteArray *message;
    message = new QByteArray;
    QDataStream out(message, QIODevice::WriteOnly);
 
    out.setVersion(QDataStream::Qt_5_4);
 
    // Оставляем два пустых байта под размер сообщения, третий байт - код, показывающий
    // как сообщение будет обработано и в конец записываем само сообщение
    out << quint16(0) << quint8(MESSAGE) << str;
 
    // Возвращаемся на начало
    out.device()->seek(0);
 
    // И дописываем в оставленные пустыми два байта размер сообщение
    // (размер только самой строки)
    out << quint16(message->size() - sizeof(quint16));
 
    // Наконец отправляем сообщение
    socket->write(message->toStdString().c_str());
    emit socket->readyRead();
    delete message;
Довольно странно, что изначально в str хранилось вот это: "(17:27:40) Alice: ывапраав", а в message оказалось 4 байта: '\0' 2 1 1

На этом все. Попытки отправки сообщений из двух первый прог реакции не вызвала.

Интересно, что при закрытии первый двух приложений сигнал disconnected() не сработал. Как так? Получается _socket подключился (connected() сработал) неизвестно куда?
0
161 / 126 / 30
Регистрация: 30.05.2015
Сообщений: 380
04.06.2015, 20:35 12
_socket один, но при получении конекта от сервера он перезаписывается другим.
Так что есть где путаться.
Накатал вот примерчик.
Код не идеален, но думаю можно что то подчерпнуть.
Вложения
Тип файла: rar Socket.rar (11.1 Кб, 20 просмотров)
1
161 / 126 / 30
Регистрация: 30.05.2015
Сообщений: 380
04.06.2015, 20:56 13
Забыл ситуацию уже установленнного соединения обратотать:

C++ (Qt)
1
2
3
4
5
6
7
8
void CharServer::onNewConnection()
{
    if (mChatHandler) {
        // уже соединение установлено
        return
    }
    
}
0
0 / 0 / 0
Регистрация: 02.06.2015
Сообщений: 22
04.06.2015, 22:24  [ТС] 14
Kurles, спасибо за пример, почитал. И с несколькими правками добился хотя бы получения сигнала readyRead()

Однако сами сообщения до сих пор теряются:
Чтение из сокета

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void MyClient::SocketReadyRead()
{
//тут обрабатываются данные от сервера
    QTcpSocket *Socket = qobject_cast<QTcpSocket*>(sender());
                                  
    QDataStream in(Socket);
//если считываем новый блок первые 2 байта это его размер
 
    if (_blockSize == 0) {
//если пришло меньше 2 байт ждем пока будет 2 байта
        if (Socket->bytesAvailable() < (int)sizeof(quint16))
            return;
//считываем размер (2 байта)
        in >> _blockSize;
    }
//ждем пока блок придет полностью
    if (Socket->bytesAvailable() < _blockSize)
        return;
    else //можно принимать новый блок
        _blockSize = 0;
//3 байт - команда серверу
    quint8 command;
    in >> command;
 
    switch (command)
    {
        default:
        case MyClient::UNSECURED_CONNECTION:
        {
 
            // todo: Обработку команды сервера о незащищенном канале (т.е. обмен ключами)
        }
        //общее сообщение от сервера
        case MyClient::MESSAGE:
        {
            //Скидываем сообщение на расшифровку
            QString message;
            in >> message;  // message получается всегда равным "", т.е. пустым
            emit NewMessage(&message);
            break;
        }
    }
}

Отправку хотелось бы оставить через QByteArray (вы же прямо QString пишете)
Запись в поток

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void MyClient::SendToClient(QTcpSocket *socket, const QString *str)
{
    QByteArray *message;
    message = new QByteArray;
    QDataStream out(message, QIODevice::WriteOnly);
 
    out.setVersion(QDataStream::Qt_5_4);
    // Оставляем два пустых байта под размер сообщения, третий байт - код, показывающий
    // как сообщение будет обработано и в конец записываем само сообщение
    out << quint16(0) << quint8(MESSAGE) << str;
 
    // Возвращаемся на начало
    out.device()->seek(0);
 
    // И дописываем в оставленные пустыми два байта размер сообщение
    // (размер только самой строки)
    out << quint16(message->size() - sizeof(quint16));
 
    // Наконец отправляем сообщение
    socket->write(*message);
    delete message;
}


Что может быть не так? На всякий случай еще раз весь проект приложу
Вложения
Тип файла: rar Encryptor_v0_1.rar (12.4 Кб, 6 просмотров)
0
161 / 126 / 30
Регистрация: 30.05.2015
Сообщений: 380
04.06.2015, 23:54 15
Я не знаю, как себя ведёт QDataStream при seek, возможно в этом причина порчи данных. Я бы для такой простой сериализации не его использовал. Опять же выделение QByteArray в стеке лишнее в тебя, как по мне...

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <QApplication>
#include <QtEndian>
#include <QDebug>
#include <QByteArray>
 
struct data {
    quint8 mode;
    QByteArray data;
};
 
QByteArray serialize(const data &value) {
    quint16 size = value.data.size() + 3;
    // место под размер
    QByteArray retVal(0x02, 0xff);
    qToLittleEndian<quint16>(size, (uchar*)retVal.data());
    retVal.append((char)value.mode);
    retVal.append(value.data);
    return retVal;
}
 
bool deserealize(const QByteArray &value, data *out) {
    if (value.size() < 3) {
        return false;
    }
    quint8 size = qFromLittleEndian<quint16>((const uchar*)value.constData());
    if (size != value.size()) {
        return false;
    }
    out->mode = (quint8)value.at(2);
    out->data = value.mid(3);
    return true;
}
 
 
 
int main(int argc, char *argv[])
{
    QString testString = QObject::tr("Я тест!!");
    data testData;
    testData.mode = 1;
    testData.data = testString.toUtf8();
    QByteArray serialized = serialize(testData);
 
 
    data testDataOut;
    if (!deserealize(serialized, &testDataOut)) {
        qDebug() << "error";
        return 0;
    }
    if (testData.mode != testDataOut.mode) {
        qDebug() << "error 2";
        return 0;
    }
    QString str = QString::fromUtf8(testDataOut.data);
    if (str != testString) {
        qDebug() << "error 3";
        return 0;
    }
 
    qDebug() << "pass";
    return 0;
}
Примерный алгоритм сериализации для твоего случая. Лучше, конечно, всё это в отдельный класс завернуть.

ну и твой метод:

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
void MyClient::SendToClient(QTcpSocket *socket, const QString *str)
{
    data x;
    x.mode = (quint8)MESSAGE;
    // можно любым способом в QByteArray QString здесь завернуть.
    x.data = str->toUtf8();
    
    // Наконец отправляем сообщение
    socket->write(serialize(x));
}
1
0 / 0 / 0
Регистрация: 02.06.2015
Сообщений: 22
05.06.2015, 02:03  [ТС] 16
Kurles, Спасибо за почти сутки советов, заработало)
0
05.06.2015, 02:03
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.06.2015, 02:03
Помогаю со студенческими работами здесь

Обмен данными через COM порт
Доброго времени суток. Требуется производить обмен данными с неким устройством через СОМ порт....

Обмен данными через таблицы
Доброго времени суток друзья! Столкнулся с проблемой обмена информацией по таблицам… Есть...

Обмен данными через Интернет
Подскажите пожалуйста, как можно организовать обмен сообщениями между двумя программами через...

Обмен данными через COM порт
Нашел исходник программы для работы с com портом. Какие есть стандартные команды, чтобы получить...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru