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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Теряется часть пакетов при работе с TcpSocket через интернет  (Прочитано 13909 раз)
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;
    }
}



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

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

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


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

Записан
SABROG
Гость
« Ответ #1 : Март 29, 2010, 09:27 »

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

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

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

Сообщений: 1053


С уважением, мастер конфетного цеха!


Просмотр профиля
« Ответ #2 : Март 29, 2010, 14:29 »

Я конечно может не в тему ,но в свое время наткнулся на шикарную реализацию RPC работает по Tcp протоколу , правда она на boost ,но на мой взгляд с ее помощью очень удобно сетевые приложения писать Улыбающийся

http://code.google.com/p/rcf-cpp/
Записан
AntonUfo
Гость
« Ответ #3 : Март 29, 2010, 14:59 »

Я конечно может не в тему ,но в свое время наткнулся на шикарную реализацию RPC работает по Tcp протоколу , правда она на boost ,но на мой взгляд с ее помощью очень удобно сетевые приложения писать Улыбающийся

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

В примерах которые разбирал когда писал прогу к сожалению этой темы не касаются, там все просто передал - принял - отключился....
Записан
Maximus
Гость
« Ответ #4 : Март 30, 2010, 16:42 »

http://ru.wikipedia.org/wiki/Tcp
В самом определении протокола TCP заложена гарантированная доставка данных. Наверно нужно ковырять QAbstractSocket и QIODevice.
QAbstractSocket::LowDelayOption
QAbstractSocket::KeepAliveOption   
Если делать докачку тогда лучше использовать QUdpSocket.
« Последнее редактирование: Март 30, 2010, 16:56 от Maximus » Записан
AntonUfo
Гость
« Ответ #5 : Март 30, 2010, 16:53 »

В самом определении протокола TCP заложена гарантированная доставка данных. Наверно нужно ковырять QTcpSocket.
Если делать докачку тогда лучше использовать QUdpSocket.

я то же так думал..., я тут поэкспериментировал...самое интересное что пакеты оказывается и через интернет нормально ходят если клиент и сервер находятся на широком канале (домовые сети к примеру), проблема с потерей появляется при работе клиента из под Yotы...
Записан
Maximus
Гость
« Ответ #6 : Март 30, 2010, 17:06 »

А браузеры, качалки, нормально работают и другие клиент-серверные приложения? Потеря пакетов и на них сказываться должна.
« Последнее редактирование: Март 30, 2010, 17:08 от Maximus » Записан
AntonUfo
Гость
« Ответ #7 : Март 30, 2010, 21:03 »

А браузеры, качалки, нормально работают и другие клиент-серверные приложения? Потеря пакетов и на них сказываться должна.

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

ЗЫ: Мне кто нибудь может объяснить нужно ли от клиента серверу каким то образом передавать инфу (ключ) что информация на i-м шаге передана успешно и полностью ?
Записан
SABROG
Гость
« Ответ #8 : Март 31, 2010, 08:48 »

В самом определении протокола TCP заложена гарантированная доставка данных. Наверно нужно ковырять QAbstractSocket и
У меня не однократно были ситуации, когда вызывается php скрипт сервера, при этом происходит таймаут по истечении 60 секунд и кирдык нужно делать вторую попытку. При этом во второй вкладке я вижу, что неотвечающий сервер нормально функционировал уже на 5ой секунде, а тупой сокет ждал его весь таймаут. Это говорит о том, что пакет с запросом скрипта до него не дошел. Сервак не падал.
Записан
AntonUfo
Гость
« Ответ #9 : Апрель 05, 2010, 11:51 »

я так еще и не разобрался....  Плачущий
Записан
SABROG
Гость
« Ответ #10 : Апрель 05, 2010, 12:35 »

я так еще и не разобрался....  Плачущий

То есть докачку уже попробовал, но она не работает?
Записан
AntonUfo
Гость
« Ответ #11 : Апрель 05, 2010, 16:06 »

я так еще и не разобрался....  Плачущий

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

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

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

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

У них очень низкая и очень нестабильная скорость на отдачу, зато на прием более менее. Устройство маленькое, передатчик дешевый и слабый по сравнению с их антеннами. Мы сидели на йоте какое-то время в центре Москвы, на цветном бульваре, впечатления остались не очень хорошие. Чтобы почту проверять и просто сайты серфить она подходит, а вот чтобы играть в онлайн игрушки или раздавать файло по торренту или закачивать фотки и т.п. - отстой. Тех поддержка на мои замеры скорости вообще ничего не ответила, я им в письме даже ID ближайшей станции отправил и кучу технической информации.
Записан
AntonUfo
Гость
« Ответ #13 : Апрель 06, 2010, 07:36 »

У них очень низкая и очень нестабильная скорость на отдачу...
я это понимаю..., у меня вопрос всетаки немного в другом, попробую сформулировать еще раз:

"На плохом (нестабильном как то к примеру наверно диал ап, ета, различные 3ж и т.д.) канале в клиент серверном приложении реализованном с помощью TcpSocket теряются часть пакетов при передаче, установившейся канал при этом не рвется, что делать ? Как вариант вижу такое решение..., вся информация которую необходимо передать копится к примеру в "списке", при отдаче сервером порции инфы она из списка не удаляется пока на сервер не придет подтверждение от клиента что он ее получил успешно, если подтверждение не приходит то сервер отправляет непроходящий блок инфы еще раз и т.д. Я думаю в правильном направлении или нет, может это велосипед и все решается как нибудь стандартно ? Кто сталкивался, кто реализовывал ?"
PS: В примерах по работе с TcpSocket ничего ненашел на эту тему, они до безобразия простые создали сервер - подконектились клиентом - передали несколько байт инфы, разъединились. Сервер который у меня написан передает инфу в процессе некоторых расчетов и ее неточто бы много но и не мало, расчеты могут длится долго и связь при этом с клиентом теряться недолжна и пакеты должны приходить все... а вот тут косяк....
Записан
SimpleSunny
Гость
« Ответ #14 : Апрель 06, 2010, 09:39 »

Та вообще-то всё это должен делать TCP. Он каждый пакет нумерует, отсылает, ждет подтверждение получения (ACK), если ACK не получен, то данные отсылает повторно.
« Последнее редактирование: Апрель 06, 2010, 10:01 от SimpleSunny » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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