Russian Qt Forum

Qt => Работа с сетью => Тема начата: AntonUfo от Март 29, 2010, 07:57



Название: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: AntonUfo от Март 29, 2010, 07:57
Всем привет. Мне необходимо было сделать многопоточный асинхронный сервер. Долго с этим вопросом разбирался, вроде сделал, во внутренней  сетке работает нормально, все пакеты приходят и уходят правильно. На сервере в нужном месте программы вызывается сигнал который в нужном потоке вызывает слот который в свою очередь отправляет непосредственно информацию. Функции слота и сервера представлены ниже:

Функция сервера (slot) подготавливающая данные для отправки:

Код:
void EchoThread::recievmessages( const QString &strmessage, const QString &arg ){
   
QByteArray block2;
    QDataStream out(&block2, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_4);
    out << quint16(0); // для последующего подсчета размера блока в байтах, пока записываем 0
out << arg;
out << strmessage;

    //подсчет колличества байтов в сформированном пакете и отсылка информации
    out.device()->seek(0);
    out << quint16(block2.size() - sizeof(quint16)); //подсчитаем реальный размер блока в байтах
   
emit writeToSocket(block2);
}
Функция клиента принимающая данные:
Код:
void RAM::updateTcpWidget()
{
QString arg;
QString strmessage;

    QDataStream in(&tcpSocket);
    in.setVersion(QDataStream::Qt_4_4);

forever {

        if (nextBlockSize == 0) {
            if (tcpSocket.bytesAvailable() < sizeof(quint16))
                break;
                in >> nextBlockSize;
        }

        if (nextBlockSize == 0xFFFF) {
connectUp = false;
            closeConnection();
            break;
        }

        if (tcpSocket.bytesAvailable() < nextBlockSize)
            break;

in >> arg;
in >> strmessage;

//вывод информации в поле вывода
if (arg == tr( "1" )){
//что то делаем по первому варианту
}
//вывод информации в статусбар
if (arg == tr( "2" )){
                        //что то делаем по второму варианту

}
}

nextBlockSize = 0;
    }
}



Вот теперь самое главное: все работает нормально только в сетке !!!! при работе через интернет ЧАСТЬ пакетов теряется !!!, я понимаю что что то не понимаю :),  соединение (сокет) при этом не рвется... Как сделать правильно, сейчас алгоритм такой (упрощенно):

Сервер готовит данные на отправку и высчитывает сколько байт содержит информация для отправки, отправляет инфу клиенту.
Клиент получает инфу о том сколько байт информации необходимо получить, получает отправленную информацию (нужное количество), проводит необходимые действия с инфой...

Может быть клиент должен еще отправлять на сервер что то типа подтверждения что он все получил правильно ? а к примеру если такого от клиента не пришло (часть пакетов потерялось) сервер отправляет туже инфу снова ?


Очень необходимо разобраться....



Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: SABROG от Март 29, 2010, 09:27
Может быть клиент должен еще отправлять на сервер что то типа подтверждения что он все получил правильно ? а к примеру если такого от клиента не пришло (часть пакетов потерялось) сервер отправляет туже инфу снова ?

У нас удаленная сетка на работе через VPN сделана, весь траффик через инет идет, при попытке передать на какой-нибудь сервак файл пусть даже размером в 1Мб часто получаем сообщение о том, что связь была неожиданно потеряна. Это дело под виндой. Если посмотреть на трассировку, то видно, что пинг до серваков 1мс, но при этом связь не стабильная, постоянно рвется и возвращается. Это никак не отражается в сетевых программах, видимо дело в таймаутах сокета. Если в течении 60 секунд связь возвращается обратно, то как бы разрыва и небыло.

В общем при таком раскладе у нас тоже пакеты теряются. Предлагаю организовать авто-докачку. Если пришел пакет с новыми данными или конец транзакции, а старый кусок получен не до конца, то шлем команду серверу, чтобы начал передачу начиная от Размер Данных минус Количество Полученных байт = Смещение от начала блока данных с которого осуществить пересылку. Где-нибудь в памяти фиксировать насколько часто происходит запрос о докачке, чтобы понять какое качество связи и принять решение о разбиении данных на более мелкие куски.


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: ecspertiza от Март 29, 2010, 14:29
Я конечно может не в тему ,но в свое время наткнулся на шикарную реализацию RPC работает по Tcp протоколу , правда она на boost ,но на мой взгляд с ее помощью очень удобно сетевые приложения писать :)

http://code.google.com/p/rcf-cpp/


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: AntonUfo от Март 29, 2010, 14:59
Я конечно может не в тему ,но в свое время наткнулся на шикарную реализацию RPC работает по Tcp протоколу , правда она на boost ,но на мой взгляд с ее помощью очень удобно сетевые приложения писать :)

да хотелось бы всетаки разобраться в том что уже сделал...
мне пока непонятно то, что я выше написал (мои догадки про ответ серверу от клиента о успешном приеме порции информации) верны или нет ?

В примерах которые разбирал когда писал прогу к сожалению этой темы не касаются, там все просто передал - принял - отключился....


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: Maximus от Март 30, 2010, 16:42
http://ru.wikipedia.org/wiki/Tcp
В самом определении протокола TCP заложена гарантированная доставка данных. Наверно нужно ковырять QAbstractSocket и QIODevice.
QAbstractSocket::LowDelayOption
QAbstractSocket::KeepAliveOption   
Если делать докачку тогда лучше использовать QUdpSocket.


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: AntonUfo от Март 30, 2010, 16:53
В самом определении протокола TCP заложена гарантированная доставка данных. Наверно нужно ковырять QTcpSocket.
Если делать докачку тогда лучше использовать QUdpSocket.

я то же так думал..., я тут поэкспериментировал...самое интересное что пакеты оказывается и через интернет нормально ходят если клиент и сервер находятся на широком канале (домовые сети к примеру), проблема с потерей появляется при работе клиента из под Yotы...


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: Maximus от Март 30, 2010, 17:06
А браузеры, качалки, нормально работают и другие клиент-серверные приложения? Потеря пакетов и на них сказываться должна.


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: AntonUfo от Март 30, 2010, 21:03
А браузеры, качалки, нормально работают и другие клиент-серверные приложения? Потеря пакетов и на них сказываться должна.

я честно говоря проблем не заметил.., ну медленно Yota относительно работает ну и что...., а вот почему мой клиент - сервер на ней пахать отказывается нормально понять немогу....

ЗЫ: Мне кто нибудь может объяснить нужно ли от клиента серверу каким то образом передавать инфу (ключ) что информация на i-м шаге передана успешно и полностью ?


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: SABROG от Март 31, 2010, 08:48
В самом определении протокола TCP заложена гарантированная доставка данных. Наверно нужно ковырять QAbstractSocket и
У меня не однократно были ситуации, когда вызывается php скрипт сервера, при этом происходит таймаут по истечении 60 секунд и кирдык нужно делать вторую попытку. При этом во второй вкладке я вижу, что неотвечающий сервер нормально функционировал уже на 5ой секунде, а тупой сокет ждал его весь таймаут. Это говорит о том, что пакет с запросом скрипта до него не дошел. Сервак не падал.


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: AntonUfo от Апрель 05, 2010, 11:51
я так еще и не разобрался....  :'(


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: SABROG от Апрель 05, 2010, 12:35
я так еще и не разобрался....  :'(

То есть докачку уже попробовал, но она не работает?


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: AntonUfo от Апрель 05, 2010, 16:06
я так еще и не разобрался....  :'(

То есть докачку уже попробовал, но она не работает?

честно говоря нет, непробовал, т.к. неуверен что так будет правильно, нехочется опять изобретать велосипед (их у меня итак много :( ), непонятно как в таком случае поступают гуру программирования ? хочется дельного совета..., если без докачки никак то конечно придется ее реализовывать...

ЗЫ: я вот понять немогу почему проблемы возникают именно с Етой... у них что какой то нестандартный TCP IP ?


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: SABROG от Апрель 05, 2010, 17:57
ЗЫ: я вот понять немогу почему проблемы возникают именно с Етой... у них что какой то нестандартный TCP IP ?

У них очень низкая и очень нестабильная скорость на отдачу, зато на прием более менее. Устройство маленькое, передатчик дешевый и слабый по сравнению с их антеннами. Мы сидели на йоте какое-то время в центре Москвы, на цветном бульваре, впечатления остались не очень хорошие. Чтобы почту проверять и просто сайты серфить она подходит, а вот чтобы играть в онлайн игрушки или раздавать файло по торренту или закачивать фотки и т.п. - отстой. Тех поддержка на мои замеры скорости вообще ничего не ответила, я им в письме даже ID ближайшей станции отправил и кучу технической информации.


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: AntonUfo от Апрель 06, 2010, 07:36
У них очень низкая и очень нестабильная скорость на отдачу...
я это понимаю..., у меня вопрос всетаки немного в другом, попробую сформулировать еще раз:

"На плохом (нестабильном как то к примеру наверно диал ап, ета, различные 3ж и т.д.) канале в клиент серверном приложении реализованном с помощью TcpSocket теряются часть пакетов при передаче, установившейся канал при этом не рвется, что делать ? Как вариант вижу такое решение..., вся информация которую необходимо передать копится к примеру в "списке", при отдаче сервером порции инфы она из списка не удаляется пока на сервер не придет подтверждение от клиента что он ее получил успешно, если подтверждение не приходит то сервер отправляет непроходящий блок инфы еще раз и т.д. Я думаю в правильном направлении или нет, может это велосипед и все решается как нибудь стандартно ? Кто сталкивался, кто реализовывал ?"
PS: В примерах по работе с TcpSocket ничего ненашел на эту тему, они до безобразия простые создали сервер - подконектились клиентом - передали несколько байт инфы, разъединились. Сервер который у меня написан передает инфу в процессе некоторых расчетов и ее неточто бы много но и не мало, расчеты могут длится долго и связь при этом с клиентом теряться недолжна и пакеты должны приходить все... а вот тут косяк....


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: SimpleSunny от Апрель 06, 2010, 09:39
Та вообще-то всё это должен делать TCP. Он каждый пакет нумерует, отсылает, ждет подтверждение получения (ACK), если ACK не получен, то данные отсылает повторно.


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: SABROG от Апрель 06, 2010, 22:34
Та вообще-то всё это должен делать TCP. Он каждый пакет нумерует, отсылает, ждет подтверждение получения (ACK), если ACK не получен, то данные отсылает повторно.
А как тогда объяснить поведение того же Firefox? Я жму ссылку, ничего не происходит секунд 10, затем открываю вторую вкладку и жму ссылку там еще раз - на этот раз всё ОК. А вот в первой вкладке по прошествии 60 секунд выдает "невозможно соединиться с сервером". То есть он даже не пытается в течении целой минуты повторно что-либо послать, тупо сидит и ждет.


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: Zmeishe от Апрель 07, 2010, 12:33
Если на "гнилых" сетях и "тощих" каналах теряются пакеты, следует зажать MTU на клиенте.
В TCP размер пакета для виндовоза по умолчанию 8К. Во внутренней сетке такие пакеты со свистом пролетают.
На модемных соединениях надо уменьшать размер пакета.
Для виндовоза MTU в реестре устанавливается.
Для Linux он по умолчанию 1.5К и ничего менять на надо.


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: AntonUfo от Апрель 13, 2010, 08:07
Если на "гнилых" сетях и "тощих" каналах теряются пакеты, следует зажать MTU на клиенте.

пипец, но это же как бы не выход наверное..., неужели никто не сталкивался....:(


Название: Re: Теряется часть пакетов при работе с TcpSocket через интернет
Отправлено: Zmeishe от Апрель 13, 2010, 08:50
В том то и дело, что сталкивался. Ещё на Qt3 в 2006 году сталкивался.
И эта проблема к Qt не имеет отношения. Поэтому средствами Qt решать её не имеет смысла.
Тут приводили пример с браузером. Но браузер использует протокол http.
Возможно http умеет на низком уровне изменять размер пакета tcp, т.к. http только надстройка над tcp.

Классы QTcpSocket и QTcpServer наверняка используют прямой сетевой API операционки.
Либо наследоваться от QTcpSocket и копать глубины API каждой операционки, либо изменить MTU в настройках операционки.
Когда сервер "снюхивается" с клиентом, они выбирают минимальный MTU, на котором они могут гарантированно инфу гонять.
Попробуй зажать на сервере, тогда с каждым клиентом не надо будет мерятся - у кого толще  :) и почему пакеты теряются.

Наши админы зажимают только на "тощих" каналах из губернии в город. У городских клиентов не трогаем. А на серваке по умолчанию.