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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: QTcpSocket QTcpServer скорости.  (Прочитано 10088 раз)
Orfus
Гость
« : Июль 21, 2011, 13:44 »

Доброго дня. Стоит необходимость передавать файлы внутри локальной сети (100Мбит/сек). Файлы передаются, вопрос только в скорости передачи.

Весь алгоритм отправки.
1) Подключился к клиенту.
2) Выбрал файл отправки.
3) Кинул имя файла и его размер.
4) Дождался ответа, что имя и размер приняты и клиент ждёт "начинку". Высылает начинку. Ниже кусок непосредственно высылающий файл.
Код
C++ (Qt)
   while(curNumber*_blockSize<=_FileSize)
   {
       qint64 a=_FileSize-curNumber*_blockSize;
       int blockSize = qMin(a,_blockSize);
       QByteArray filearr=FileForSend->read(blockSize);
           sock->write(filearr);
           curNumber++;
   }
 
5) Дождался  сообщения что файл принят и просчитал среднюю скорость передачи.

Алгорит приёма.
1) Приём подключения от сервера. QTcpServer стоит на стороне клиента  Смеющийся
2) Приём имени файла и его размера.
3) Приём содержимого файла.
Код
C++ (Qt)
quint64 currentSize=0,curBytesAv=0;
   while(currentSize < FileSize){
       curBytesAv=socket->bytesAvailable();
       if(curBytesAv>0){
           QByteArray arr;
           arr = sock->read(curBytesAv);
           if(curBytesAv==arr.size()){
               FileForRec->write(arr);
               currentSize+=curBytesAv;
               }
           }
       if(currentSize < FileSize)
           sock->waitForReadyRead();
   }
 
4) Считает среднюю скорость передачи и высылает подтверждение приёма.
5) ждёт следующую шапку файла.


Далее имеется несколько машин:
A - 3ггц, 1 гиг оперативки, 1Гигабит сетевая,  WinXp
B - 2.6ггц, 768 мб оперативки, 100Мегабит ,WinXp
C - 3.2ггц, 1 гиг оперативки, 100Мегабит, Vista

Собственно говоря проблема в следующем:
имеется тестовый файл размером в 50МегаБайт который я перекидываю:

с А->A скорость 250+мегабит
c A->B ~50мегабит
с А->C ~8мегабит

c B->B ~50мегабит
c С->C ~50 мегабит
c B->A ~50 мегабит

Я понимаю что выше 100мегабит скорость не получить, но вот почему она в определенных случаях такая маленькая понять не могу. Подскажите в какую сторону смотреть? Возможно нужно какие-то настройки сокетов через Api править? Я не вижу как ещё можно ускорить алгоритм отправки и приёма.
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #1 : Июль 21, 2011, 14:41 »

_blockSize чему равен?
Записан
Orfus
Гость
« Ответ #2 : Июль 21, 2011, 14:51 »

_blockSize чему равен?
1480 байт, насколько вычитал 1500 это максимальный предел.
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #3 : Июль 21, 2011, 15:06 »

1) Для сравнения попробуйте поставить значительно большее значение (раз в 10 хотя бы).
2) Попробуйте погонять файлы через, скажем Total Commander и посмотрите скорость там.
Записан
SimpleSunny
Гость
« Ответ #4 : Июль 21, 2011, 16:27 »

Как посоветовали выше читать и писать блоками большего размера + желательно проверять, что отправили все что пытались отправить.

Запись
Код
C++ (Qt)
QFile file;
QTcpSocket socket;
...
const qint64 blockSize = 8192;
char buffer[blockSize];
while (!file.atEnd())
{
   qint64 sizeRead = file.read(buffer, blockSize);
   if (sizeRead > 0)
   {
       qint64 sizeWrite = 0
do
    {
       qint64 size = socket->write(buffer + sizeWrite, sizeRead - sizeWrite);
       if (size < 0)
           return;
       sizeWrite += size;
} while (sizeWrite < sizeRead);
   }
}
 

Чтение
Код
C++ (Qt)
QFile file;
QTcpSocket socket;
qint64 sizeFile;
...
qint64 sizeAll = 0;
qint64 offset = 0;
const qint64 blockSize = 8192;
char buffer[blockSize];
while (sizeAll < sizeFile)
{
   socket.waitForReadyRead();
   qint64 size = socket->read(buffer, qMin(blockSize - offset, sizeFile - sizeAll));
   if (size < 0)
       return;
   offset += size;
   sizeAll += size;
 
   if (offset == blockSize || sizeAll == sizeFile)
   {
       qint64 sizeWrite = 0;
       do
       {
           qint64 size = file.write(buffer + sizeWrite, offset - sizeWrite);
           if (size < 0)
               return;
           sizeWrite += size;
       } while (sizeWrite < offset);
 
       offset = 0;
   }
}
 
Записан
Orfus
Гость
« Ответ #5 : Июль 21, 2011, 19:54 »

LisandreL,SimpleSunny спасибо за советы)
Как вы и говорили, дело по большей части было в размере блоков. Я наивно предполагал что сам составляю начинку пакета, а это было не так. Сегодня накидаю код виджета меняющего размер блоков без пересборки проекта, а завтра буду тестить. По резултату отпишусь. Улыбающийся

Кстати говоря вот такая штука  в отправке файла
Код
C++ (Qt)
sock->write(filearr);
sock->waitForBytesWritten(15);
дала прирост в 1МегаБайт. Думаю ещё поковырять её.
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #6 : Июль 21, 2011, 21:52 »

Я наивно предполагал что сам составляю начинку пакета
TCP — это поток данных. В отличии от UDP он не передаёт блоки целиком, а волен нарезать или склеивать(!) их так, как ему заблагорассудится (вернее как это реализовано в данной конкретной ОС).
Записан
Orfus
Гость
« Ответ #7 : Июль 25, 2011, 10:16 »

При размере блока в 64мегабайта (благо оперативки нынче везде много  Смеющийся ) добился скорости в ~86Мбит, для файлов ~300Мбайт. Впринципе меня такая скорость уже устраивает, но всё же скажите имеет ли смысл писать следующий блок по пришествии сигнала
Код:
  void QIODevice::bytesWritten ( qint64 bytes ) [signal]
Или это уже пустая трата времени в погоне за оставшимися 14 мегабитами  Улыбающийся
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #8 : Июль 25, 2011, 10:44 »

Или это уже пустая трата времени в погоне за оставшимися 14 мегабитами
О всех 14 даже не мечтайте. Не менее 5% идёт на служебную информацию в пакетах: http://sd.wareonearth.com/~phil/net/overhead/
Записан
Orfus
Гость
« Ответ #9 : Июль 25, 2011, 11:08 »

О всех 14 даже не мечтайте. Не менее 5% идёт на служебную информацию в пакетах: http://sd.wareonearth.com/~phil/net/overhead/
Но получается часть из них ещё можно получить? Просто после того как в торрент клиенте видел 12МБайт\сек с 1го конкретного локального пира, считаю это число достижимым Строит глазки 

P.S.
Хотя это наверно уже лишнее. Передавать огромные файлы (>100мб) я не планировал, а для небольших человек физически разницы не увидит. Ещё раз спасибо за советы.
Записан
Gabriel.vs
Гость
« Ответ #10 : Август 16, 2011, 15:13 »

Для увеличения скорости обмена данными в сети надо:
* Отключить "Nigle Algorithm" (m_sslSocket->setSocketOption(QAbstractSocket::LowDelayOption, 0)). Вот только не помню - возможно она по-умолчанию уже выключена.
* Максимально уменьшить время, подставляемое в waitForReadyRead(), а ещё лучше эти методы на сигналы переписать. Как показали тесты, когда я переписывал VNC под реализацию в Qt, значение в waitForReadyRead крайне сильно влияло на задержки. Пришлось в единицу выставлять. Можно ещё вот в этом посте почитать (http://www.prog.org.ru/index.php?topic=17649.msg118258#msg118258), относительно скорости самих сокетов Qt'шных.
* после каждого сенда даты flush() вызывать.
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #11 : Август 16, 2011, 15:22 »

Просто после того как в торрент клиенте видел 12МБайт\сек с 1го конкретного локального пира
Вообще-то многие клиенты как раз считают скорость со всем оверхедом, а не только полезных данных.
Ну а так - в примерах Qt есть торрент клиент. Можете поэкспериментировать на предмет его максимальной скорости в локалке.
Записан
Orfus
Гость
« Ответ #12 : Август 17, 2011, 16:22 »

Для увеличения скорости обмена данными в сети надо:
* Отключить "Nigle Algorithm" (m_sslSocket->setSocketOption(QAbstractSocket::LowDelayOption, 0)). Вот только не помню - возможно она по-умолчанию уже выключена.
После мучений с keepalive я сомневаюсь что setSocketOption вообще работает.

* Максимально уменьшить время, подставляемое в waitForReadyRead(), а ещё лучше эти методы на сигналы переписать. Как показали тесты, когда я переписывал VNC под реализацию в Qt, значение в waitForReadyRead крайне сильно влияло на задержки. Пришлось в единицу выставлять. Можно ещё вот в этом посте почитать (http://www.prog.org.ru/index.php?topic=17649.msg118258#msg118258), относительно скорости самих сокетов Qt'шных.
На сигналы то переписанное у меня как раз медленнее работало. Всё в одном слоте давало большую скорость.
waitForReadyRead(1) попробую на досуге, по умолчанию там 30.000
По поводу кютешных сокетов. 86МБит меня вполне устраивает  Подмигивающий Да, моя реализация кушала память весьма активно, но скушанные 100мб (а больше файлы с 90% вероятностью пересылатся не будут) меня не печалят, тем более что по окончанию отправки они освобождались.

* после каждого сенда даты flush() вызывать.
Это тоже стоит опробовать.

Собственно говоря как гласит пословица "Если хочешь сделать хорошо - сделай это сам.". Было бы больше времени, я бы расписывал отправку/приём более детально, ну а пока что меня устраивает вариант с чтением по 64мегабайт при отправке.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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