Russian Qt Forum

Qt => Работа с сетью => Тема начата: winneru от Октября 11, 2009, 21:47



Название: Передача файлов по сети
Отправлено: winneru от Октября 11, 2009, 21:47
Помогите, пожалуйста. Необходимо организовать передачу файла через сеть, используя в качестве адреса получателя его IP адрес. Как сделать это с помощью UDP? Или может быть есть другой способ? Заранее спасибо


Название: Re: Передача файлов по сети
Отправлено: registrationfedser87 от Октября 12, 2009, 09:36
Передачу файлов лучше наверно по протоколу TCP делать. Посмотри QTcpServer,QTcpSocket, а также пример Loopback Example.


Название: Re: Передача файлов по сети
Отправлено: winneru от Октября 12, 2009, 10:01
большое спасибо.а может быть как то через udp можно?Я читал что с помощью udp организуется даже предача потокового видео по сети.Наверное и файл передать можно


Название: Re: Передача файлов по сети
Отправлено: registrationfedser87 от Октября 12, 2009, 10:25
передать то и по UDP можно,но UDP(в отличии от TCP) не гарантирует доставку пакета, т.е. проверку доставлен ли каждый пакет до получателя или нет придётся проводить самому.


Название: Re: Передача файлов по сети
Отправлено: winneru от Октября 12, 2009, 12:01
Насчет небезопасности и ненадежности я в курсе.Это не важно.Так может ты все таки знаешь как передачу через udp организовать?Надо считать файл в поток?Подскажи пожалуйста в каком хотя бы направлении двигаться.Буду очень признателен


Название: Re: Передача файлов по сети
Отправлено: registrationfedser87 от Октября 12, 2009, 12:17
А что у тебя не получается? Скажу сразу я файл через UDP не передавал.  Ты можешь разбить файл на куски и передать их пакетами. На принимающей стороне получать эти пакеты и собирать их в один файл (быть может надо передавать ещё номер части файла). После того как передана последняя часть отсылаешь какой-нибудь информирующий пакет клиенту что передача завершена


Название: Re: Передача файлов по сети
Отправлено: winneru от Октября 12, 2009, 12:26
Вот я и хотел узнать каким образом произвести разбиение на пакеты.Я без труда разобрался как с помощью writeDatagram() посылать текстовые сообщения.Просто объявлять эти сообщения через QByteArray.А вот как засунуть вместо текста файл?


Название: Re: Передача файлов по сети
Отправлено: TukiNov от Октября 12, 2009, 12:43
сам щас пишу клиент сервер.
вот как я читаю файл и отправляю паки
Код:
    file.open(QFile::ReadOnly);
    QDataStream read(&file);
    lBytes = 0;
    char * ch;
    ch = (char*)malloc(sizeof(char) * 1024);
    ch[1023] = '\0';
    while(!read.atEnd()){
      int l = read.readRawData(ch, sizeof(char)*1023);
      QByteArray ba(ch, sizeof(char)*l);

      lBytes += m_pTcpSocket->write(ba, sizeof(char)*l);
      m_pTcpSocket->flush();
      if (-1 == lBytes){
        qWarning() << "Error";
        m_pTcpSocket->close(); //Закрываем устройство сокета
        return;
      }
      float procentage = ((float)lBytes / package.filelength) * 100;
      emit setProcentage((int)procentage);
    }//while(!readEnd())
    free((void*)ch);


Название: Re: Передача файлов по сети
Отправлено: winneru от Октября 12, 2009, 12:51
Большое спасибо.Я просто методы не те использовал.И этот код уже рабочий,разбивает и отправляет?


Название: Re: Передача файлов по сети
Отправлено: TukiNov от Октября 12, 2009, 12:53
Большое спасибо.Я просто методы не те использовал.И этот код уже рабочий,разбивает и отправляет?
ну да. 100% рабочий. Его и использую. отправляет пакеты по 1024. Моно и больше сделать.


Название: Re: Передача файлов по сети
Отправлено: winneru от Октября 12, 2009, 12:56
Бесконечно благодарен.А насчет udp не знаешь?


Название: Re: Передача файлов по сети
Отправлено: TukiNov от Октября 12, 2009, 12:59
Бесконечно благодарен.А насчет udp не знаешь?
я не писал под UDP, но каж там все также как и с TCP. Поменяй QTcpSocket * m_pTcpSocket на QUdpSocket и все. Глянь ассистент по поводу отправки пакетов по UDP :)


Название: Re: Передача файлов по сети
Отправлено: winneru от Октября 12, 2009, 13:07
А вот ты написал мне код для разбиения и отправки, а для принятия их на клиете тоже отдельный код нужен или он будет сам в текущую папку сохранять?


Название: Re: Передача файлов по сети
Отправлено: TukiNov от Октября 12, 2009, 13:15
А вот ты написал мне код для разбиения и отправки, а для принятия их на клиете тоже отдельный код нужен или он будет сам в текущую папку сохранять?
Канеш нуно писать прием :) Я свой протокол реализовывал, сначала слал пакет с описанием, ну например, размер фала, имя файла, а потом уже начинал отправку.
на стороне сервера прием:
Код:
  QFile save(package.filename);
  save.open(QFile::WriteOnly);
  QDataStream write(&save);

  long int lBytesDone = 0; //Пока ничего не приняли
  long int lSize = package.filelength;
  long int lBytes;
  while (lBytesDone < lSize){//Пока приняли меньше, чем указано
    //Ожидаем данные
    lBytes = 0;
    while (lBytes == 0) lBytes = m_pTcpSocket->waitForReadyRead(-1);
    if (-1 == lBytes){//Если произошла ошибка сокета, то
      qWarning("-----TFileServer: Aborting download.");
      m_pTcpSocket->close();
      return;
    }//if (-1 == lBytes)
    QByteArray tmp = m_pTcpSocket->readAll();
    lBytes += write.writeRawData(tmp.data(), tmp.size());
    lBytesDone += tmp.size();
    float procentage = ((float)lBytes / package.filelength) * 100;
    emit setProcentage((int)procentage);
  }//while (lBytesDone < lSize)
  save.close();


Название: Re: Передача файлов по сети
Отправлено: BRE от Октября 12, 2009, 13:26
2 TukiNov
Несколько вопросов/комментариев.  :)
* Почему malloc, а не new?
* Для чего нужен QDataStream? У QFile есть свой метод read, который читает нужное количество байт и возвращает готовый QByteArray (malloc/free не понадобятся).
* У QTcpSocket есть метод write, который в качестве параметра получает QByteArray.


Название: Re: Передача файлов по сети
Отправлено: winneru от Октября 12, 2009, 13:38
Ты меня просто спас.То есть это уже готовые коды и для клиента и для сервера?


Название: Re: Передача файлов по сети
Отправлено: TukiNov от Октября 12, 2009, 13:47
2 TukiNov
Несколько вопросов/комментариев.  :)
* Почему malloc, а не new?
* Для чего нужен QDataStream? У QFile есть свой метод read, который читает нужное количество байт и возвращает готовый QByteArray (malloc/free не понадобятся).
* У QTcpSocket есть метод write, который в качестве параметра получает QByteArray.
Ну теоретически моно уйти от char, malloc, free :) Но прога в первую очередь заточена под МСВС :) а там граблей с Qt4 хватает :) Да и мне проще так регулировать размер пакета. А так все комменты по делу :)


Название: Re: Передача файлов по сети
Отправлено: TukiNov от Октября 12, 2009, 13:47
Ты меня просто спас.То есть это уже готовые коды и для клиента и для сервера?
ну да. Только это просто обработка входящий данных и отправка :) сам сервер - клиент тебе писать :)


Название: Re: Передача файлов по сети
Отправлено: TukiNov от Октября 12, 2009, 13:50
2 TukiNov
Несколько вопросов/комментариев.  :)
* Для чего нужен QDataStream? У QFile есть свой метод read, который читает нужное количество байт и возвращает готовый QByteArray (malloc/free не понадобятся).
qint64 QIODevice::read ( char * data, qint64 maxSize )
QByteArray QIODevice::read ( qint64 maxSize )
Первая все равно в char* кидает, вторая не подходит


Название: Re: Передача файлов по сети
Отправлено: BRE от Октября 12, 2009, 15:26
qint64 QIODevice::read ( char * data, qint64 maxSize )
QByteArray QIODevice::read ( qint64 maxSize )
Первая все равно в char* кидает, вторая не подходит
Почему не подходит?


Название: Re: Передача файлов по сети
Отправлено: TukiNov от Октября 12, 2009, 22:00
qint64 QIODevice::read ( char * data, qint64 maxSize )
QByteArray QIODevice::read ( qint64 maxSize )
Первая все равно в char* кидает, вторая не подходит
Почему не подходит?
а как с помощью её прочитать от фрагмент ?(не с начала файла а например с середины)


Название: Re: Передача файлов по сети
Отправлено: BRE от Октября 12, 2009, 22:01
а как с помощью её прочитать от фрагмент ?(не с начала файла а например с середины)
Не понял?  :o
Точно также как и с помощью qint64 QIODevice::read ( char * data, qint64 maxSize ).




Название: Re: Передача файлов по сети
Отправлено: BRE от Октября 12, 2009, 22:21
Еще несколько моментов.
Код
C++ (Qt)
   file.open(QFile::ReadOnly);
   QDataStream read(&file);
   lBytes = 0;
   char * ch;
   ch = (char*)malloc(sizeof(char) * 1024);
   ch[1023] = '\0';
   while(!read.atEnd()){
     int l = read.readRawData(ch, sizeof(char)*1023);
     QByteArray ba(ch, sizeof(char)*l);
 
     lBytes += m_pTcpSocket->write(ba, sizeof(char)*l);
     m_pTcpSocket->flush();
// !!! проверка будет работать корректно только при первой операции записи в сокет (т.к. lBytes += ...)
     if (-1 == lBytes){
       qWarning() << "Error";
       m_pTcpSocket->close();
// !!! при ошибке будет "течь" память (буфер ch не освобождается)
       return;
     }
     float procentage = ((float)lBytes / package.filelength) * 100;
     emit setProcentage((int)procentage);
   }//while(!readEnd())
   free((void*)ch);
 


Название: Re: Передача файлов по сети
Отправлено: TukiNov от Октября 13, 2009, 09:00
Еще несколько моментов.
Код
C++ (Qt)
   file.open(QFile::ReadOnly);
   QDataStream read(&file);
   lBytes = 0;
   char * ch;
   ch = (char*)malloc(sizeof(char) * 1024);
   ch[1023] = '\0';
   while(!read.atEnd()){
     int l = read.readRawData(ch, sizeof(char)*1023);
     QByteArray ba(ch, sizeof(char)*l);
 
     lBytes += m_pTcpSocket->write(ba, sizeof(char)*l);
     m_pTcpSocket->flush();
// !!! проверка будет работать корректно только при первой операции записи в сокет (т.к. lBytes += ...)
     if (-1 == lBytes){
       qWarning() << "Error";
       m_pTcpSocket->close();
// !!! при ошибке будет "течь" память (буфер ch не освобождается)
       return;
     }
     float procentage = ((float)lBytes / package.filelength) * 100;
     emit setProcentage((int)procentage);
   }//while(!readEnd())
   free((void*)ch);
 

Спасиб :) с этим согласен :) упустил :) было lBytes =, но решил переменную использовать в подсчете процентов :) исправлю :)


Название: Re: Передача файлов по сети
Отправлено: BRE от Октября 13, 2009, 09:04
Спасиб :) с этим согласен :) упустил :) было lBytes =, но решил переменную использовать в подсчете процентов :) исправлю :)
Попробуй сделать чтение/запись на функциях работающих с QByteArray. Думаю код упроститься, по крайней мере буфер уйдет.
P.S. В подобных случаях, буфер ch лучше выделять на стеке, тогда и проблем с освобождением не будет.


Название: Re: Передача файлов по сети
Отправлено: TukiNov от Октября 13, 2009, 12:31
Спасиб :) с этим согласен :) упустил :) было lBytes =, но решил переменную использовать в подсчете процентов :) исправлю :)
Попробуй сделать чтение/запись на функциях работающих с QByteArray. Думаю код упроститься, по крайней мере буфер уйдет.
P.S. В подобных случаях, буфер ch лучше выделять на стеке, тогда и проблем с освобождением не будет.

Оке, попробую.
Слух, у мя тут вопрос созрел.
У меня клиент, начинает передавать файл как только установили соединение, то есть в connectedServer()
Код:
m_pTcpSocket = new QTcpSocket();
  connect(m_pTcpSocket, SIGNAL(connected()), SLOT(connectedServer()));
а сервер обрабатывает входящие соединения в
Код:
void ThreadServer::run()
{
  m_pTcpSocket = new QTcpSocket();
  if(!m_pTcpSocket->setSocketDescriptor(socketDescriptor)){
    qDebug() << m_pTcpSocket->errorString();
    return;
  }
...
...
...
чё то мне кажется я не правильно сделал :)


Название: Re: Передача файлов по сети
Отправлено: BRE от Октября 13, 2009, 14:10
Клиент
Можно это делать и синхронно:
Код
C++ (Qt)
socket->connectToHost( ... );
if( !socket->waitForConnected( timeout ) )
{
// ОШИБКА: Соединение не произошло
}
 
// Начали передачу данных
 

Сервер
Я правильно понял, что ты в обработчике сигнала newConnection, запускаешь поток, который будет обслуживать данное подключение?
Если да, то можно использовать сам объект QTcpSocket, который возвращает nextPendingConnection ():
Код
C++ (Qt)
void Server::slot_newConnection()
{
QTcpSocket *client = nextPendingConnection();
if( !client )
return;
 
Thread *t = new Thread( client );
t->start();
}
 
Thread::Thread( QTcpSocket *socket )
{
Q_ASSERT( m_client );
m_client = socket;
m_client->moveToThread( this );
}
 
void Thread::run()
{
// работает с сокетом клиента m_client
}
 
И не забываем убивать объект m_socket при disconnect.