crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )


  Ответ в Куда теряются пакеты ? QTcpServer QTcpClient, блокирующие сокеты
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
Теги
Выровнять по центру
Ссылка на тему
Ссылка на сообщение
Скрытый текст
Сокращение
Код с подсветкой
Offtopic
 
Удалить форматирование
Спец. элементы
Шрифт
Размер
 
Цвет шрифта
 
Отменить ввод
Вернуть ввод
Полужирный
Курсив
Подчеркнутый
 
 
Смайлики
Вставить изображение
Вставить адрес электронной почты
Цитата
Код
Раскрывающийся текст
 
Увеличить отступ
По левому краю
По центру
По правому краю
Вставить список
Вставить список

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
pirks Дата 29.8.2009, 18:42
  Я понял в чём таки трабла !!!

Мой алгоритм (и все его версии) ПРАВЕЛЬНЫЕ. Всё дело было в том что я создавал сокет в основном потоке, а потом передовал в поток его дескриптор. Видемо функции работы с сетью в QT не всегда рентабельны.
Перенёс создание сокета в сам поток и всё отлично теперь работает.

Благодарю всех за внимание, тему можно считать закрытой.
pirks Дата 25.7.2009, 21:23
 
Цитата(kuzulis @ 25.7.2009, 18:36) *
Цитата
В принципе ясно. Только в пункте 4 - если не читать любое доступное колличество байт, а при несовпадении с неким минимально допустимым размером куска данных, сделать waitForReadyRead и затем считать кусок большего размера.

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

Цитата
К примеру мне пришло 3 байта, а я хочу считать за раз 4, т.к. у меня размер пакета 4 байта.
При таком подходе данные в буфере не затираются вновь прибывшими пакетами ?


если пришло 3 байта, то bytesAvailable() покажет что пришло в данный момент 3 байта.. и за раз нужно читать 3 байта... а потом уже в следующий раз (если прочитали не весь пакет) - опять сделать waitForReadyRead() и когда он отработает (т.е когда придет снова хотя-бы 1 байт) - сделать опять то bytesAvailable() и считать из буфера уже например 1 байт, чтобы получился весь пакет!

далее... после операции чтения те данные которые уже прочитали - больше не прочитаются.. т.к. типа они "затрутся", так что волноваться не о чем :)

Цитата
Вот интересно - если мой код находиться в слоте readyRead () и используются неблокирующие сокеты. то всё отлично работает :) .

неправда! не будет отлично работать т.к. readyRead () срабатывает только если приходит хотя-бы один байт! И если например мы ожидаем пакет в 1000 байт, и срабатывает readyRead () - то это не значит что в буфер пришли все 1000 байт.. это значит что пришло >=1 байта! Поэтому если мы выполним операцию чтения read(1000) - то не факт что мы прочитаем 1000 байт за раз!
И в этом случае нужно ловить сигнал readyRead() lдо тех пор, пока мы не прочитаем ВСЕ 1000 байт (по частям)! И я все-таки предпочитаю принцип который изложил выше, т.к. если постоянно полагаться на radyRead() - то можно где - нить накосячить... Хотя.. нужно смотреть по обстакановке

ИМХО :)


Я проверяю на наличие нужного мне колличества байт. И при отсутсвии нужного мне колличества байт жду ..

newRead

void RecvThread::newRead ()
{
    // если в blockSize == 0 то мы не считали размер пакета
    if (blockSize == 0)
        {
            // проверяем доступность хотя бы 2 байтов
            //для считывания заголовка пакета
            if (newTcpSocket.bytesAvailable() >= (int)sizeof(quint16))
            {
                // собственно читаем наши 2 байта, содержащие в себе размер пакета
                in >> blockSize;
            }
        }

        // если данных достаточно. то читаем весь пакет, нет ждём следующей порции
        if (newTcpSocket.bytesAvailable() >= blockSize)
        {
            // забираем данные
            in >> temp1;
            in >> temp2;
            in >> temp3;
            in >> temp4;
            in >> temp5;
            in >> temp6;
            in >> temp7;
            in >> temp8;
            in >> temp9;
            in >> temp10;
            blockSize = 0; // так как пакет считан, обнуляем его размер
            QString msg = "recv - "
                + QString::number(temp1, 10) + " "
                + QString::number(temp2, 10) + " "
                + QString::number(temp3, 10) + " "
                + QString::number(temp4, 10) + " "
                + QString::number(temp5, 10) + " "
                + QString::number(temp6, 10) + " "
                + QString::number(temp7, 10) + " "
                + QString::number(temp8, 10) + " "
                + QString::number(temp9, 10) + " "
                + QString::number(temp10, 10);
            qDebug (msg.toAscii());
        }
}

void RecvThread::run() // Функция выполнения потока
{
    in.setDevice( &newTcpSocket ); // связываем поток с сокетом
    in.setVersion(QDataStream::Qt_4_4);
    blockSize = 0;

    while (newTcpSocket.waitForReadyRead(-1))
    {
        newRead ();
    }
}

kuzulis Дата 25.7.2009, 17:36
 
Цитата
В принципе ясно. Только в пункте 4 - если не читать любое доступное колличество байт, а при несовпадении с неким минимально допустимым размером куска данных, сделать waitForReadyRead и затем считать кусок большего размера.

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

Цитата
К примеру мне пришло 3 байта, а я хочу считать за раз 4, т.к. у меня размер пакета 4 байта.
При таком подходе данные в буфере не затираются вновь прибывшими пакетами ?


если пришло 3 байта, то bytesAvailable() покажет что пришло в данный момент 3 байта.. и за раз нужно читать 3 байта... а потом уже в следующий раз (если прочитали не весь пакет) - опять сделать waitForReadyRead() и когда он отработает (т.е когда придет снова хотя-бы 1 байт) - сделать опять то bytesAvailable() и считать из буфера уже например 1 байт, чтобы получился весь пакет!

далее... после операции чтения те данные которые уже прочитали - больше не прочитаются.. т.к. типа они "затрутся", так что волноваться не о чем :)

Цитата
Вот интересно - если мой код находиться в слоте readyRead () и используются неблокирующие сокеты. то всё отлично работает :) .

неправда! не будет отлично работать т.к. readyRead () срабатывает только если приходит хотя-бы один байт! И если например мы ожидаем пакет в 1000 байт, и срабатывает readyRead () - то это не значит что в буфер пришли все 1000 байт.. это значит что пришло >=1 байта! Поэтому если мы выполним операцию чтения read(1000) - то не факт что мы прочитаем 1000 байт за раз!
И в этом случае нужно ловить сигнал readyRead() lдо тех пор, пока мы не прочитаем ВСЕ 1000 байт (по частям)! И я все-таки предпочитаю принцип который изложил выше, т.к. если постоянно полагаться на radyRead() - то можно где - нить накосячить... Хотя.. нужно смотреть по обстакановке

ИМХО :)
pirks Дата 25.7.2009, 11:25
  Вот интересно - если мой код находиться в слоте readyRead () и используются неблокирующие сокеты. то всё отлично работает :) . а если ТОТ ЖЕ самый код поместить в поток в цыкле типа

while (newTcpSocket.waitForReadyRead(-1))
    {
        newRead (); // в этой функции находиться обработка данных с сокета
    }


Ведь получается что цыкл иметирует слот readyRead () , следовательно принципиальной разници нет. Или я не прав ? :blink:
SABROG Дата 24.7.2009, 19:47
 
Цитата(pirks @ 24.7.2009, 19:42) *
При таком подходе данные в буфере не затираются вновь прибывшими пакетами ?


если readAll() не вызывал, то данные будут "валяться" в буффере до тех пор, пока их не заберешь, а новые добавляться к существующим. Если надо просто взглянуть, что находится в буффере без его очистки, то можно использовать метод peek().
pirks Дата 24.7.2009, 18:42
 
Цитата(kuzulis @ 22.7.2009, 15:52) *
2 pirks,

смотри какой принцип чтения из сокета использую Я :

1. делаем waitForReadyRead(таимаут ожидания прихода пакета); // ожидаем прихода хотябы одного байта в сокет
2. если ф-я в п.1 вернула true - то к П.3. иначе говорим что таймаут ожидания байтов
3. делаем bytesAvailable() //получаем количество пришедших в сокет байт
4. если >0 то читаем это количество байт иначе говорим что ошибка
4.1 приплюсовываем прочитанные данные к тем, которые прочитали на предыдущем шаге.. и если их длина буит = длине ожидаемого пакета то возвращаем пакет , иначе к п.5.
5. делаем waitForReadyRead(таймаут ожидания прихода следующего символа) //если пакет прочитали не весь -здесь можно ставить 1-5 мс (т.е мы уверены, что следующий пакет придет только через 1-5 мс и мы не прочитаем кусок из следующего пакета)
6. если в п.5. вернула true то переходим к п.3 иначе возвращаем все прочитанные ранее данные (при этом можно не возвращать их)

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


В принципе ясно. Только в пункте 4 - если не читать любое доступное колличество байт, а при несовпадении с неким минимально допустимым размером куска данных, сделать waitForReadyRead и затем считать кусок большего размера.
К примеру мне пришло 3 байта, а я хочу считать за раз 4, т.к. у меня размер пакета 4 байта.
При таком подходе данные в буфере не затираются вновь прибывшими пакетами ?
kuzulis Дата 22.7.2009, 14:52
  2 pirks,

смотри какой принцип чтения из сокета использую Я :

1. делаем waitForReadyRead(таимаут ожидания прихода пакета); // ожидаем прихода хотябы одного байта в сокет
2. если ф-я в п.1 вернула true - то к П.3. иначе говорим что таймаут ожидания байтов
3. делаем bytesAvailable() //получаем количество пришедших в сокет байт
4. если >0 то читаем это количество байт иначе говорим что ошибка
4.1 приплюсовываем прочитанные данные к тем, которые прочитали на предыдущем шаге.. и если их длина буит = длине ожидаемого пакета то возвращаем пакет , иначе к п.5.
5. делаем waitForReadyRead(таймаут ожидания прихода следующего символа) //если пакет прочитали не весь -здесь можно ставить 1-5 мс (т.е мы уверены, что следующий пакет придет только через 1-5 мс и мы не прочитаем кусок из следующего пакета)
6. если в п.5. вернула true то переходим к п.3 иначе возвращаем все прочитанные ранее данные (при этом можно не возвращать их)

кароч идея дкмаю ясна... при таком подходе ничо теряться не будет и такой подход можно использовать - поставив на ожидание чтение из сокета
(это в случае если мы не знаем когда данные придут.. ведь не обязательно сразу после коннекта они будут приходить ) ;)
ViGOur Дата 22.7.2009, 9:25
 
Цитата(pirks @ 22.7.2009, 7:14) *
а узких мест по склейке пакеов я не вижу. Я проверяю пакеты на целостность и жду ) Не вижу траблы.
pirks, ты не исправим.

Судя по всему ты совсем недавно начал изучать сокеты, да и по стилю программирования С\С++ также недолго изучаешь, пол года максимум год.
Или это какой-то непонятный стеб!

Тебе уже все описали, разжевали, только вот код не написали, а ты все гнешь свою линию! Ладно был бы прав и были бы железные теоретические или практические аргументы, а вот нет, обычное пустозвонство... С такой позицией как у тебя, тебе никто не будет писать код, так как он простой и видно, что ты просто не хочешь думать...

Цитата(kwisp @ 22.7.2009, 8:56) *
так значит у тебя всё работает!!! поздравляю.:)
:)
kwisp Дата 22.7.2009, 7:56
 
Цитата(pirks @ 22.7.2009, 7:14) *
а узких мест по склейке пакеов я не вижу. Я проверяю пакеты на целостность и жду ) Не вижу траблы.

так значит у тебя всё работает!!! поздравляю.:)

П.С.
чего тогда вопросы задавать? надо наслаждаться кропотливым жужжанием своей программы, раз "траблов" нет:)
pirks Дата 22.7.2009, 6:14
 
Цитата(ViGOur @ 21.7.2009, 23:46) *
Цитата(pirks @ 21.7.2009, 23:24) *
Сокеты это сокеты беркли ) их я знаю. Это давным давно придуманная технология. Всё остальное эт обёртки. Они нужны только для упрощения и кросплатформенности.
Если бы это было так, то не нужно было бы виндовый сокеты (WSA) скрещивать с BSD cокетами (беркли) с макросами ifdef UNIX и прочими. Хоть сокеты Windows и разработанный на основе сокетов Беркли, но частично. Чтобы убедиться в этом глянь кроссплатформенные реализации Boost (asio), ACE, POCO, Qt ...

Ты споришь не там где нужно, лучше прочти мой последний ответ тебе, я описал в чем проблемы.


хм, сокеты виндовс..... да это в принципе они ничего сами не писали, взяли бсдишные и закрыли исходники! первая версия это один в один, за исключением инициализации, самого типа дескриптора да названия парочки структур )))
Мелкософт в принципе не способен сам придумать ничего нормального. всё покупают да переделывают.

>>pirks, очень сложно помочь человеку, если он не слушает советы. Перечитай сообщения ViGOur(а), найди у себя в коде указанные узкие места и попробуй их переделать - >>возможно, и поможет! ;)

я переделывал по разному, а узких мест по склейке пакеов я не вижу. Я проверяю пакеты на целостность и жду ) Не вижу траблы.
Просмотр темы полностью (откроется в новом окне)
RSS Рейтинг@Mail.ru Текстовая версия Сейчас: 4.7.2025, 22:28