crossplatform.ru

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


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

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
 

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


Последние 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 Текстовая версия Сейчас: 29.3.2024, 14:22