Я знаю, что некоторые подобные вопросы, возможно, уже заданы, но ответы на те, которые я нашел, охватывали очень специфические проблемы, и я до сих пор не понял этого.QTcpSocket: чтение и письмо
В моей программе я создаю QObject (QPeer), который использует QTcpSocket для связи с другим таким объектом по сети. QPeer имеет слот, который принимает QByteArray с данными (sendData(QByteArray)
). Все содержимое этого массива считается одним «сообщением», и они записываются в сокет. Я хочу сделать следующее: каждый раз, когда сообщение записывается, я хочу, чтобы принимающий QPeer выдавал свой сигнал dataReceived(QByteArray)
ровно один раз, что QByteArray содержит все сообщение. (Примечание:. Все сигналы/слоты, как частные, соединяющие QPeer с его гнездом и общественные, такие как те, sendData(QByteArray)
сериализуются с помощью Qt::QueuedConnection
всякий раз, когда это необходимо)
Я использую сигнал QTcpSocket::readyRead()
для асинхронного чтения из сокета. Теперь я знаю, что не могу просто позвонить QTcpSocket::write()
один раз в sendData, а затем предположить, что для каждой записи, которую я делаю, QTcpSocket с другой стороны производит ровно один сигнал readyRead. И что же мне делать?
Это моя идея, пожалуйста, скажите мне, если это будет работать:
ЗАПИСЬ:
void QPeer::sendData(QByteArray data)
{
// TODO: write data.size() as raw int of exactly 4 bytes to socket
const char *bytes = data.constData();
int bytesWritten = 0;
while (bytesWritten < data.size())
bytesWritten += _socket->write(bytes + bytesWritten);
}
ЧТЕНИЕ:
теперь я хочу функцию чтения (подключенный к QTcpSocket::readyRead()
) использовать заголовок (4 байта int, определяющий длину сообщения), а затем прочитайте это количество байтов; next emit dataReceived с точно этими байтами. У меня серьезные проблемы с этим. Например: что делать, если readyRead испускается, и я могу прочитать заголовок сообщения, но не количество байтов, указанное? Или что, если заголовок был получен только частично?
1. Как правильно записать заголовок (4 байта int) в сокет?
2. Как правильно реализовать функцию чтения, чтобы она выполняла то, что я хочу?
Любые советы приветствуются. Благодаря!
Большое спасибо! Предыдущий ответ сработал, но это заставило меня пересмотреть мой класс. Все стало немного ... противно. – DiscobarMolokai
Однако быстрый вопрос: когда ваш сервер получает своего первого клиента (newConnection вызывается в первый раз), член сокета содержит указатель на сокет для этого соединения. Но что, если через несколько мгновений встретится новое входящее соединение, а newConnection вызывается снова. Тогда предыдущий сокет потерян, не так ли? Или механизм сигнала/слота по-прежнему работает на этом сокете? – DiscobarMolokai
Сигнал будет излучаться, потому что сокет является указателем, он не будет уничтожен в конце области действия, за исключением случаев, когда вы вызываете 'delete' или используете интеллектуальный указатель, однако вы больше не можете получать данные из этого соединения, метод 'readyRead()' будет работать только с указателем, хранящимся в нашей переменной (последний подключенный клиент). Для работы с несколькими клиентами вам потребуется создать несколько экземпляров класса, содержащего ваш собственный указатель сокета и соответствующий буфер. –