crossplatform.ru

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

3 страниц V  < 1 2 3  
Ответить в данную темуНачать новую тему
> Куда теряются пакеты ? QTcpServer QTcpClient, блокирующие сокеты
kwisp
  опции профиля:
сообщение 22.7.2009, 7:56
Сообщение #21


астарожна ынтжинэр
*****

Группа: Участник
Сообщений: 1404
Регистрация: 26.11.2008
Из: ТаганрогРодинаЧехова
Пользователь №: 435

Спасибо сказали: 113 раз(а)




Репутация:   23  


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

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

П.С.
чего тогда вопросы задавать? надо наслаждаться кропотливым жужжанием своей программы, раз "траблов" нет:)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 22.7.2009, 9:25
Сообщение #22


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


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

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

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

Цитата(kwisp @ 22.7.2009, 8:56) *
так значит у тебя всё работает!!! поздравляю.:)
:)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kuzulis
  опции профиля:
сообщение 22.7.2009, 14:52
Сообщение #23


Активный участник
***

Группа: Участник
Сообщений: 393
Регистрация: 29.6.2009
Пользователь №: 862

Спасибо сказали: 36 раз(а)




Репутация:   7  


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 иначе возвращаем все прочитанные ранее данные (при этом можно не возвращать их)

кароч идея дкмаю ясна... при таком подходе ничо теряться не будет и такой подход можно использовать - поставив на ожидание чтение из сокета
(это в случае если мы не знаем когда данные придут.. ведь не обязательно сразу после коннекта они будут приходить ) ;)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
pirks
  опции профиля:
сообщение 24.7.2009, 18:42
Сообщение #24


Студент
*

Группа: Участник
Сообщений: 21
Регистрация: 5.7.2009
Пользователь №: 876

Спасибо сказали: 1 раз(а)




Репутация:   0  


Цитата(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 байта.
При таком подходе данные в буфере не затираются вновь прибывшими пакетами ?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 24.7.2009, 19:47
Сообщение #25


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Цитата(pirks @ 24.7.2009, 19:42) *
При таком подходе данные в буфере не затираются вновь прибывшими пакетами ?


если readAll() не вызывал, то данные будут "валяться" в буффере до тех пор, пока их не заберешь, а новые добавляться к существующим. Если надо просто взглянуть, что находится в буффере без его очистки, то можно использовать метод peek().

Сообщение отредактировал SABROG - 24.7.2009, 19:48
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
pirks
  опции профиля:
сообщение 25.7.2009, 11:25
Сообщение #26


Студент
*

Группа: Участник
Сообщений: 21
Регистрация: 5.7.2009
Пользователь №: 876

Спасибо сказали: 1 раз(а)




Репутация:   0  


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

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


Ведь получается что цыкл иметирует слот readyRead () , следовательно принципиальной разници нет. Или я не прав ? :blink:
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kuzulis
  опции профиля:
сообщение 25.7.2009, 17:36
Сообщение #27


Активный участник
***

Группа: Участник
Сообщений: 393
Регистрация: 29.6.2009
Пользователь №: 862

Спасибо сказали: 36 раз(а)




Репутация:   7  


Цитата
В принципе ясно. Только в пункте 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, 21:23
Сообщение #28


Студент
*

Группа: Участник
Сообщений: 21
Регистрация: 5.7.2009
Пользователь №: 876

Спасибо сказали: 1 раз(а)




Репутация:   0  


Цитата(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 ();
    }
}

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
pirks
  опции профиля:
сообщение 29.8.2009, 18:42
Сообщение #29


Студент
*

Группа: Участник
Сообщений: 21
Регистрация: 5.7.2009
Пользователь №: 876

Спасибо сказали: 1 раз(а)




Репутация:   0  


Я понял в чём таки трабла !!!

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

Благодарю всех за внимание, тему можно считать закрытой.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

3 страниц V  < 1 2 3
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 25.4.2024, 19:39