Russian Qt Forum

Qt => Работа с сетью => Тема начата: Orfus от Июль 21, 2011, 13:44



Название: QTcpSocket QTcpServer скорости.
Отправлено: 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 стоит на стороне клиента  ;D
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 править? Я не вижу как ещё можно ускорить алгоритм отправки и приёма.


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: LisandreL от Июль 21, 2011, 14:41
_blockSize чему равен?


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: Orfus от Июль 21, 2011, 14:51
_blockSize чему равен?
1480 байт, насколько вычитал 1500 это максимальный предел.


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: LisandreL от Июль 21, 2011, 15:06
1) Для сравнения попробуйте поставить значительно большее значение (раз в 10 хотя бы).
2) Попробуйте погонять файлы через, скажем Total Commander и посмотрите скорость там.


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: SimpleSunny от Июль 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;
   }
}
 


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: Orfus от Июль 21, 2011, 19:54
LisandreL,SimpleSunny спасибо за советы)
Как вы и говорили, дело по большей части было в размере блоков. Я наивно предполагал что сам составляю начинку пакета, а это было не так. Сегодня накидаю код виджета меняющего размер блоков без пересборки проекта, а завтра буду тестить. По резултату отпишусь. :)

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


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: LisandreL от Июль 21, 2011, 21:52
Я наивно предполагал что сам составляю начинку пакета
TCP — это поток данных. В отличии от UDP он не передаёт блоки целиком, а волен нарезать или склеивать(!) их так, как ему заблагорассудится (вернее как это реализовано в данной конкретной ОС).


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: Orfus от Июль 25, 2011, 10:16
При размере блока в 64мегабайта (благо оперативки нынче везде много  ;D ) добился скорости в ~86Мбит, для файлов ~300Мбайт. Впринципе меня такая скорость уже устраивает, но всё же скажите имеет ли смысл писать следующий блок по пришествии сигнала
Код:
  void QIODevice::bytesWritten ( qint64 bytes ) [signal]
Или это уже пустая трата времени в погоне за оставшимися 14 мегабитами  :)


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: LisandreL от Июль 25, 2011, 10:44
Или это уже пустая трата времени в погоне за оставшимися 14 мегабитами
О всех 14 даже не мечтайте. Не менее 5% идёт на служебную информацию в пакетах: http://sd.wareonearth.com/~phil/net/overhead/


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

P.S.
Хотя это наверно уже лишнее. Передавать огромные файлы (>100мб) я не планировал, а для небольших человек физически разницы не увидит. Ещё раз спасибо за советы.


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: Gabriel.vs от Август 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 (http://www.prog.org.ru/index.php?topic=17649.msg118258#msg118258)), относительно скорости самих сокетов Qt'шных.
* после каждого сенда даты flush() вызывать.


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: LisandreL от Август 16, 2011, 15:22
Просто после того как в торрент клиенте видел 12МБайт\сек с 1го конкретного локального пира
Вообще-то многие клиенты как раз считают скорость со всем оверхедом, а не только полезных данных.
Ну а так - в примерах Qt есть торрент клиент. Можете поэкспериментировать на предмет его максимальной скорости в локалке.


Название: Re: QTcpSocket QTcpServer скорости.
Отправлено: Orfus от Август 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 (http://www.prog.org.ru/index.php?topic=17649.msg118258#msg118258)), относительно скорости самих сокетов Qt'шных.
На сигналы то переписанное у меня как раз медленнее работало. Всё в одном слоте давало большую скорость.
waitForReadyRead(1) попробую на досуге, по умолчанию там 30.000
По поводу кютешных сокетов. 86МБит меня вполне устраивает  ;) Да, моя реализация кушала память весьма активно, но скушанные 100мб (а больше файлы с 90% вероятностью пересылатся не будут) меня не печалят, тем более что по окончанию отправки они освобождались.

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

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