Russian Qt Forum

Qt => Работа с сетью => Тема начата: RomiX от Февраль 15, 2012, 19:52



Название: Отправить файл по сети
Отправлено: RomiX от Февраль 15, 2012, 19:52
Плз помогите отправить файл через QTcpSocket и принять с помощью QTcpServer. Уже пол дня мучаюсь, вроде все отправляется, и приходит, но файл создаётся пустым(((
отправка: (сори за кривоватый код)

Код:
QFile file(fileName);
    if(!file.open(QIODevice::ReadOnly)) {
        // err str
        return false;
    }
    if(!socket->isValid()) {
        return false;
    }

    socket->waitForConnected();

    QDataStream read(&file);
    QByteArray arr;
    QDataStream out(&arr, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_7);
    char data[PACKET_SIZE];
    int readed;

    out << quint16(0) << QString("file") << QFileInfo(file.fileName()).fileName() << file.size();
    out.device()->seek(0);
    out << quint16(arr.size() - sizeof(quint16));

    socket->write(arr);
    socket->flush();
    while(!read.atEnd()) {
        readed = read.readRawData(*(&data), PACKET_SIZE);
        QByteArray array(*(&data), PACKET_SIZE);
        socket->write(array);
    }

Приём:
Код:
QTcpSocket *clientSocket = (QTcpSocket *)sender();
    QDataStream in(clientSocket);
    in.setVersion(QDataStream::Qt_4_7);

    qDebug() << "read" << clientSocket->bytesAvailable();
    for(;;) {
        if(!nextBlockSize) {
            if(clientSocket->bytesAvailable() < sizeof(quint16))
                break;
            in >> nextBlockSize;
        }

        if(clientSocket->bytesAvailable() < nextBlockSize)
            break;

        QString type;
        in >> type;

        if(type == "file") { // принимаем файл
            QString fileName;
            quint64 size;

            in >> fileName;
            in >> size;

            QFile file(fileName);
            if(!file.open(QIODevice::WriteOnly)) {
                qDebug() << "can't open file to write";
                return;
            }
            qDebug() << "----------" << fileName << size;

            QDataStream fileOut(&file);

            int readed;
            quint64 done = 0;
            while(done < size) {
                /*readed = 0;
                while(readed == 0)
                    readed = clientSocket->waitForReadyRead(-1);
                if(readed == -1) {
                    qDebug() << "socket err";
                    return;
                }*/

                QByteArray tmp;
                tmp = clientSocket->readAll();
                fileOut.writeRawData(tmp.data(), tmp.size());
                done += tmp.size();
                qDebug() << "writed" << tmp.size();
                break;
            }
            qDebug() << "done";
            file.close();
            return;
        } else if (type == "text") {

        }


        nextBlockSize = 0;
    }

мне кажется я чето намудрил с чтением данных из сокета


Название: Re: Отправить файл по сети
Отправлено: merke от Февраль 16, 2012, 10:43
Извини, но какая то у тебя извращенная передача файлов. глянь на фортун сервер из примеров кутишных и сделай по примеру


Название: Re: Отправить файл по сети
Отправлено: RomiX от Февраль 16, 2012, 18:38
так по его примеру и пытался делать, тока каким образом передать большой файл(около 10МБ)?? нельзя же его просто засунуть в сокет? или всётаки можно? (тогда все упроститься)


Название: Re: Отправить файл по сети
Отправлено: merke от Февраль 16, 2012, 18:48
засунь, а на той стороне считывай пока не получишь весь файл


Название: Re: Отправить файл по сети
Отправлено: merke от Февраль 16, 2012, 18:50
Код:
out << quint16(0) << QString("file") << QFileInfo(file.fileName()).fileName() << file.size() << "сам файл";
    out.device()->seek(0);
    out << quint16(arr.size() - sizeof(quint16));


Название: Re: Отправить файл по сети
Отправлено: RomiX от Февраль 16, 2012, 18:58
интересно... и скока так получиться отправить? на скока озу хватит?


Название: Re: Отправить файл по сети
Отправлено: merke от Февраль 16, 2012, 18:59
хоть сколько)


Название: Re: Отправить файл по сети
Отправлено: BRE от Февраль 16, 2012, 19:03
хоть сколько)
И для хранения размера пакета хватит quint16?  ::)


Название: Re: Отправить файл по сети
Отправлено: merke от Февраль 16, 2012, 19:03
хоть сколько)
И для хранения размера пакета хватит quint16?  ::)

вечерняя невнимательность) это не ко мне вопрос, а к автору)


Название: Re: Отправить файл по сети
Отправлено: RomiX от Февраль 16, 2012, 19:05
спс, заюзаю quint64, получается файл читается порционно, по мере необходимости и не занимая много памяти?


Название: Re: Отправить файл по сети
Отправлено: merke от Февраль 16, 2012, 19:10
спс, заюзаю quint64, получается файл читается порционно, по мере необходимости и не занимая много памяти?

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


Название: Re: Отправить файл по сети
Отправлено: RomiX от Февраль 16, 2012, 19:14
спс, щас попробую, а принимать получается вот так:
while(done < size) ? или как то иначе?


Название: Re: Отправить файл по сети
Отправлено: BRE от Февраль 16, 2012, 19:17
Для такой отправки файл придется загрузить в память полностью, а это не всегда возможно, поэтому если нужна универсальность, то резать на части и отправлять частями.


Название: Re: Отправить файл по сети
Отправлено: RomiX от Февраль 16, 2012, 19:38
частями то я отправил вроде... а вот как это дело принять потом?


Название: Re: Отправить файл по сети
Отправлено: BRE от Февраль 16, 2012, 19:39
частями то я отправил вроде... а вот как это дело принять потом?
В смысле?
Получил кусок - дописАл в файл, получил следующий - еще дописАл. :)


Название: Re: Отправить файл по сети
Отправлено: RomiX от Февраль 16, 2012, 20:22
т.е. когда приходит имя файла и его размер, создавать сам файл, и выходить из readyRead(), а потом когда начнут приходить остальные куски (т.е. будет вызываться readyRead()) писать их в файл?


Название: Re: Отправить файл по сети
Отправлено: neversleep от Февраль 16, 2012, 21:18
т.е. когда приходит имя файла и его размер, создавать сам файл...
И НЕ выходя из readyRead в цикле получаешь содержимое файла.
Код
C++ (Qt)
QString fileName = имя_файла;
qint64 fileSizeIn = размер_фала;
qint64 fileSizeOut = 0; // сюда заносится размер полученных данных
 
QFile file(fileName);
if (file.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
   do {
       fileSizeOut += file.write(socket.readAll());
   } while (fileSizeOut < fileSizeIn && socket.waitForReadyRead());
   file.close();
}
 
if (fileSizeOut == fileSizeIn) // файл получен
 


Название: Re: Отправить файл по сети
Отправлено: BRE от Февраль 16, 2012, 21:26
И НЕ выходя из readyRead в цикле получаешь содержимое файла.
Для чего этот экстремализм? Для чего останавливать программу на время чтения одного файла? А если нужно получать сразу 100 файлов? :)
Пришла полная секция - запиши ее в файл.


Название: Re: Отправить файл по сети
Отправлено: RomiX от Февраль 16, 2012, 22:29
спс, а что если в отдельном потоке это запустить?
2BRE: что значит пришла полная секция? и как поймать данное событие


Название: Re: Отправить файл по сети
Отправлено: BRE от Февраль 16, 2012, 22:42
2BRE: что значит пришла полная секция? и как поймать данное событие
На одной стороне:
- читаешь из файла кусок (например 256 Kb)
- готовишь пакет: <размер куска> <данные куска>
- отправляешь данный пакет
- повторяешь, пока не закончиться файл

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




Название: Re: Отправить файл по сети
Отправлено: neversleep от Февраль 17, 2012, 06:36
И НЕ выходя из readyRead в цикле получаешь содержимое файла.
Для чего этот экстремализм? Для чего останавливать программу на время чтения одного файла? А если нужно получать сразу 100 файлов? :)
Пришла полная секция - запиши ее в файл.
А если цель программы скопировать только 1 файл? :)


Название: Re: Отправить файл по сети
Отправлено: RomiX от Февраль 17, 2012, 08:22
спс! как попробую напишу