crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

3 страниц V   1 2 3 >  
Ответить в данную темуНачать новую тему
> Передача данных в отдельном потоке. Сервер не успевает обработать данные.
kibsoft
  опции профиля:
сообщение 13.4.2010, 20:29
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 180
Регистрация: 21.7.2009
Из: Самара
Пользователь №: 928

Спасибо сказали: 14 раз(а)




Репутация:   2  


Есть сервер и клиент (отсылает данные, например файл):
Клиент:
void FileSender::sendFile()
{
    QFile file(filePath);
    if (file.open(QIODevice::ReadOnly)) {//если файл открылся
        QByteArray dataForPeer;//массив для данных
        QDataStream out(&dataForPeer, QIODevice::WriteOnly);//выходной поток
        QByteArray byteArray;//поток байтов из файла
        while(!file.atEnd()) {//пока не конец файла
             byteArray=file.read(1024);//читаем по килобайту
             out << quint16(0) << FILEBYTES << byteArray;
             out.device()->seek(0);
             out << quint16(dataForPeer.size() - sizeof(quint16));
             tcpSocket->write(dataForPeer);

             dataForPeer.clear();//очищаем массив для отправки серверу
        }
        //отправка уведомления об окончании передачи файла
        out << quint16(0) << SENDING_FINISHED;
        out.device()->seek(0);
        out << quint16(dataForPeer.size() - sizeof(quint16));
        tcpSocket->write(dataForPeer);

        file.close();//закрываем файл
    }
}


На сервере есть слот, соединенный с сигналом readyRead сокета, но видимо данные приходят так быстро, что сервер не успевает сделать нужные действия (а именно записать на диск). Что можно придумать? Можно ли как то на клиенте узнать считаны ли данные сервером или нет(и ждать этого момента)? В голову приходит только одно: от сервера высылать уведомление о принятых данных, чтобы клиент мог дальше передавать их (но мне кажется, что что-то не то).
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 13.4.2010, 20:40
Сообщение #2


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Покажи как читаются данные на другой стороне.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kibsoft
  опции профиля:
сообщение 13.4.2010, 20:43
Сообщение #3


Участник
**

Группа: Участник
Сообщений: 180
Регистрация: 21.7.2009
Из: Самара
Пользователь №: 928

Спасибо сказали: 14 раз(а)




Репутация:   2  


/*
  Слот для обработки принятых из сокета данных.
*/
void FileWriter::readBytes()
{
    QTcpSocket *tcpSocket=(QTcpSocket*)sender();//получаем сокет
    QDataStream in(tcpSocket);
    quint16 nextBlockSize=0;//размер принятого блока
    for(;;) {
        if(!nextBlockSize) {
            if(tcpSocket->bytesAvailable()<sizeof(quint16)) break;//если данных принято меньше 2 байт, то выходим

            in>>nextBlockSize;//получаем размер блока
        }

        if(tcpSocket->bytesAvailable()<nextBlockSize) break;//если все данные получены, то продолжаем работать

        quint8 request;//получаем запрос
        in>>request;
        TypeOfRequest type=(TypeOfRequest)request;
        if (type==FILEBYTES) {//если данные - файл, то записываем их на жесткий диск
            writeBytes(in);
        }
        else if (type==SENDING_FINISHED) {//если пир окончил отправку файла, то отправляем ему
            sendFinishMessage(tcpSocket);//уведомление об окончании его принятия
        }
        nextBlockSize=0;
    }  
}

/*
  Функция записи принятых данных в файл. Параметры: поток данных из сокета(reference).
*/
void FileWriter::writeBytes(QDataStream &in)
{
    QByteArray bytes;
    in>>bytes;//получаем нужные байты
    QFile file("D:/ref.dat");
    if (file.open(QIODevice::Append)) {
        file.write(bytes);//записываем байты
        file.close();
    }
}


/*
  Функция отправки сообщения об окончании принятия файла. Параметры: принимающий сокет.
*/
void FileWriter::sendFinishMessage(QTcpSocket *tcpSocket)
{
    QByteArray dataForPeer;//массив для данных
    QDataStream out(&dataForPeer, QIODevice::WriteOnly);//выходной поток
    out << quint16(0) << quint8(RECEIVING_FINISHED);//соообщение об окончании
    out.device()->seek(0);
    out << quint16(dataForPeer.size() - sizeof(quint16));
    tcpSocket->write(dataForPeer);
}
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 13.4.2010, 20:49
Сообщение #4


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Посмотри примеры еще раз и обрати внимание на то, как определена эта переменная:
void FileWriter::readBytes()
{
    ....
    quint16 nextBlockSize=0;//размер принятого блока
    ....

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kibsoft
  опции профиля:
сообщение 13.4.2010, 21:02
Сообщение #5


Участник
**

Группа: Участник
Сообщений: 180
Регистрация: 21.7.2009
Из: Самара
Пользователь №: 928

Спасибо сказали: 14 раз(а)




Репутация:   2  


Цитата(BRE @ 13.4.2010, 21:49) *
Посмотри примеры еще раз и обрати внимание на то, как определена эта переменная:
void FileWriter::readBytes()
{
    ....
    quint16 nextBlockSize=0;//размер принятого блока
    ....

Спасибо, что подсказали. Объявил в хедере. Но все равно сервер не успевает записывать данные.
В консоль вывел количество раз запуска слота и записи данных. Передается файл размером 42Кб:
Цитата
1 //слот о принятии данных вызван
Writing: 1 //запись
Writing: 2
2
3
4
5
6

На самом деле, если я передаю по 1 Кб, то дожно быть около 42 вызовов.. Или я что-то не так думаю?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 13.4.2010, 21:05
Сообщение #6


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Может быть не так, алгоритм Нагла думаю включен, поэтому TCP-стек скорее всего пакеты объединяет.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kibsoft
  опции профиля:
сообщение 14.4.2010, 0:03
Сообщение #7


Участник
**

Группа: Участник
Сообщений: 180
Регистрация: 21.7.2009
Из: Самара
Пользователь №: 928

Спасибо сказали: 14 раз(а)




Репутация:   2  


Цитата(BRE @ 13.4.2010, 22:05) *
Может быть не так, алгоритм Нагла думаю включен, поэтому TCP-стек скорее всего пакеты объединяет.


Щас продебажил, на сервере (в слоте обработки) сокет действительно собирает пакеты не по 1024 байта, как отсылаются, а иногда по 30Кб даже, поэтому мой обработчик естественно не может определить по флагам(FILEBYTES) нужно ли записывать инфу. Как можно этого избежать? Если отключить алгоритм Нагла, то будет в разы медленней? И вообще можно ли его отключить? И вообще есть у кого-то какие-нибудь предложения?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 14.4.2010, 6:49
Сообщение #8


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


А не нужно отключать алгоритм Нагла, нужно придерживаться при чтении своего же протокола.
Ты пишешь по 1K, а при чтении читаешь все, со всеми управляющими командами. А нужно читать так же как пишешь по 1K.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kibsoft
  опции профиля:
сообщение 14.4.2010, 13:21
Сообщение #9


Участник
**

Группа: Участник
Сообщений: 180
Регистрация: 21.7.2009
Из: Самара
Пользователь №: 928

Спасибо сказали: 14 раз(а)




Репутация:   2  


Цитата(BRE @ 14.4.2010, 7:49) *
А не нужно отключать алгоритм Нагла, нужно придерживаться при чтении своего же протокола.
Ты пишешь по 1K, а при чтении читаешь все, со всеми управляющими командами. А нужно читать так же как пишешь по 1K.

Т.е. не использовать QDataStream, а использовать read у объекта сокета? Не совсем понимаю как это реализовать.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 14.4.2010, 14:08
Сообщение #10


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Проверь несколько раз, сколько байт (какими порциями) реально читает эта функция из сокета:
void FileWriter::writeBytes(QDataStream &in)
{
    QByteArray bytes;
    in>>bytes;

    qDebug() << "Read data size from socket:" << bytes.size();

    QFile file("D:/ref.dat");
    if (file.open(QIODevice::Append)) {
        file.write(bytes);//записываем байты
        file.close();
    }
}

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

3 страниц V   1 2 3 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 6.7.2022, 10:37