Russian Qt Forum
Ноябрь 22, 2024, 14:03 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Работа с QTcpSocket  (Прочитано 6100 раз)
Yury
Гость
« : Январь 26, 2018, 13:34 »

Всем привет.
Пишу клиент-серверное приложение по передаче файлов по сети и есть вопрос.
Как только на сервере я записываю данные в сокет методом write(),то на каждый его вызов на клиенте срабатывает сигнал readyRead(), правильно?И каждый сигнал обрабатывается слотом.
А если я на сервере вызову в цикле 10 раз метод write() с новым QByteArray каждый раз в качестве аргумента?На клиенте мне приходит только самый первый пакет,остальные 9 почему-то не доходят,хотя с сервера вроде ушли.

В чем может быть дело?И как мне лучше переслать 10 файлов с сервера на клиент?
Записан
Yury
Гость
« Ответ #1 : Январь 26, 2018, 13:37 »

Вот мой код:

void MainWindow::sendToServer(const QString &msg)
{
    Package package;
    package.smallNum = 4;
    package.bigNum = 1567;
    package.str = msg;
    package.array = "jkgferwgfrewjfwewef";

    QByteArray arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_8);

    out << package.smallNum;
    out << package.bigNum;
    out << package.str;
    out << package.array;

    int lBytes = 0;

    lBytes = tcpSocket->write(arrBlock);

    qDebug() << lBytes << "were sent";
}

void MainWindow::slotConnected()
{
    ui->textEdit->append("Recieved the connected() signal from server");
}

void MainWindow::slotSendButton()
{
    int packageNum = 0;
    for(int i = 0; i < 10; ++i) {
    packageNum++;
    sendToServer("Hello, server. How are you? " + QString::number(packageNum));
    }
}

То есть по нажатию кнопки 10 раз вызовется wriye(), а на другом конце сигнал readyRead() срабатывает только раз.Иногда 2)
Записан
vicprog
Гость
« Ответ #2 : Январь 26, 2018, 14:18 »

Как мне кажется, ты забыл сделать после

Код:
tcpSocket->write(arrBlock);
tcpSocket->flush();

Размер пакета для tcp в среднем около 1500 байт. Посчитай сам, сколько туда твоих сообщений поместится.
Записан
Yury
Гость
« Ответ #3 : Январь 26, 2018, 14:26 »

С flush() уже доходит 2 пакета,но все равно не все)Остальные 8 теряются.Размер одного отсылаемого пакета тут около 90 байт,не больше 100.
Записан
vicprog
Гость
« Ответ #4 : Январь 26, 2018, 14:40 »

Посмотрите, что flush возвращает.
Еще можно поставить waitForBytesWritten() и тоже посмотреть что возвращает.
А еще посмотрите на размер приходящих пакетов. Может они спресовались в один пакет?
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #5 : Январь 26, 2018, 14:43 »

Несколько пакетов может объединяться в один readyRead, все ли данные вычитываются?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #6 : Январь 26, 2018, 15:16 »

Цитировать
Как только на сервере я записываю данные в сокет методом write(),то на каждый его вызов на клиенте срабатывает сигнал readyRead(), правильно?И каждый сигнал обрабатывается слотом.

Нет. QTcpSocket полностью асинхронный. Вызов QTcpSocket::write() пишет данные во внутренний буффер кдасса QTcpSocket, а уже там, далее эти данные могут быть посланы позже. Все зависит от внутреннего сосояния QTcpSocket и платформы на которой он реализован.

В общем случае вот это:

Код:
void Foo::bar()
{
    socket.write('A');
    socket.write('B');
    socket.write('C');
}

Не гарантирует что оно будет отослано по-отдельности и прямо сейчас.
Оно все зависит от фазы луны, настроект сокета и прочего всего. Улыбающийся

Скорее всего QTcpSocket возмет сразу ABC и запишет в FIFO драйвера (а может и не сразу),
а как там уже драйвер отправит их, одному Лешему известно. 
Записан

ArchLinux x86_64 / Win10 64 bit
Yury
Гость
« Ответ #7 : Январь 26, 2018, 15:34 »

Да,вы правы!Приходят не по отдельности пакеты,а вместе скомканные.А как их тогда лучше обработать,чтобы разделить на клиенте?Сначала в буфер записать и потом вычленять из него?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #8 : Январь 26, 2018, 16:10 »

Цитировать
Сначала в буфер записать

QTcpSocket уже имеет буфер, т.о. нет необходимости в каком-то дополнительном буфере (но тут кому как удобнее).

Цитировать
и потом вычленять из него?

Да, для этого нужно иметь какой-то протокол обмена (типо придумать заголовки к данными, типа 0x55AA).
Для парсинга данных достаточно юзать peek(), read(), bytesAvailable().
Записан

ArchLinux x86_64 / Win10 64 bit
vicprog
Гость
« Ответ #9 : Январь 26, 2018, 16:31 »

Все зависит от решаемой задачи. Если клиент может подождать и обработать потом пачку сообщений - то да, делать как в предыдущем сообщении.
Если нельзя накапливать и нужна реакция на каждое сообщение - то смотреть в сторону QUdpSocket (но там возможна потеря сообщений при передачи).
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.146 секунд. Запросов: 23.