2013-11-29 4 views
3

Теперь сервер (реализованный с Java) будет посылать некоторые потоковые данные мне, мой код, как показано ниже:Как читать полные данные в QTcpSocket?

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

в read_from_server():

{ 
    while (socket->bytesAvailable()) 
    { 
     QString temp = socket->readAll(); 
    } 
} 

, но я считаю, что даже сервер послал мне строка с несколькими символами, данные усекаются, и моя функция вызывается дважды, поэтому temp - это никогда не завершенные данные, которые я хочу.
Если сервер отправляет мне более длинную строку, моя функция может быть вызвана три или более раз, что затрудняет мне знать, когда данные передаются полностью.
Так кто-нибудь может сказать мне, как полностью получить данные легко, без так много шагов беспокоиться? Простите, если это дублируется с некоторыми вопросами, я не могу получить ответы на них. Большое спасибо!

ответ

10

То, что вы видите, это нормально для связи клиента с сервером. Данные отправляются в пакетах, а сигнал readyRead информирует вашу программу о наличии данных, но не имеет понятия о том, что и сколько данных имеется, поэтому вам нужно это обработать.

Для правильного считывания данных вам понадобится буфер, как указано в @ratchetfreak, для добавления байтов, когда они считываются из потока. Важно знать формат отправляемых данных, чтобы знать, когда у вас есть полное сообщение. Для этого я использовал, по крайней мере, два метода:

1) Убедитесь, что отправленные сообщения начинаются с размера в байтах отправляемого сообщения. При получении данных вы начинаете с чтения размера и продолжаете добавлять свой буфер до тех пор, пока он не достигнет ожидаемого размера.

2) Отправляйте все данные в известном формате, например JSON или XML, которые могут быть проверены на конец сообщения. Например, в случае JSON все пакеты начинаются с открывающей скобки '{' и заканчиваются закрывающей скобкой '}', поэтому вы можете подсчитывать фигурные скобки и сопоставлять данные или использовать QJsonDocument :: fromRawData, чтобы убедиться, что данные завершены.

Используя оба этих метода, я рекомендую использовать первый; укажите размер отправляемого сообщения.

+0

О «2», считая фигурные скобки, будет проблемой, если объект содержит строки с фигурными скобками.Лучше попробуйте правильно разобрать его и предположите, что он не является полным, если он терпит неудачу. –

+0

Я полностью согласен, вам нужно принять это во внимание и также проверять строки, хотя я упоминал использование QJsonDocument для проверки данных. Спасибо, что выделили это: 0) – TheDarkKnight

+0

@ Merlin069 Спасибо за ваш опыт! – yakiang

2

Если все данные еще не получены, ваш цикл while будет преждевременно покидать. Вам необходимо использовать формат сообщения, который позволит определить код приема, когда получено полное сообщение. Например, сообщение может начинаться с элемента длины, или если вы имеете дело с текстом, сообщение может заканчиваться некоторым символом, используемым в качестве терминатора.

+0

Спасибо, я попрошу сервер добавить символ окончания :) – yakiang

2

вы можете использовать поле буфера для временного хранения незавершенных данных и обработки пакетов, как они завершают:

{ 
    while (socket->bytesAvailable()) 
    { 
     buffer.append(socket->readAll()); 
     int packetSize = getPacketSize(buffer); 
     while(packetSize>0) 
     { 
      handlePacket(buffer.left(packetSize); 
      buffer.remove(0,packetSize); 
      packetSize = getPacketSize(buffer); 
     } 
    } 
} 
1

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

Проверьте, не помогает ли this answer (есть трюк, ожидающий ожидаемого блока данных).

+0

Спасибо за обмен :) как вы сказали, я получу какой-то способ определить, когда заканчивается блок – yakiang