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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Непонятки с QTcpSocket  (Прочитано 7088 раз)
ploop
Гость
« : Январь 28, 2014, 09:58 »

Имеется такой код, вызывается по таймеру раз в секунду:
Код
C++ (Qt)
void send_to_client()
{
 char buf[5] = {'1','2','3','4','5'};
 socket->write(buf,5);
 socket->flush();
}
 
// На другой стороне
 
void slotReadyRead()
{
 qDebug() << QTime::currentTime() << socket->readAll();
}
Вот что получаю:
Код:
QTime("10:42:44") "12345" 
QTime("10:42:45") "1234512345"
QTime("10:42:46") "1234512345"
QTime("10:42:47") "1234512345"
QTime("10:42:48") "12345"
QTime("10:42:48") "12345"
QTime("10:42:49") "1234512345"
QTime("10:42:50") "1234512345"
QTime("10:42:51") "1234512345"

Дебаг (и лог) явно показывает, что send_to_client вызывается один раз. При этом на клиенте ловим повторяющиеся данные.
Если размер посылки небольшой (помещается в один сетевой пакет), то алгоритм нормально её декодирует (повтор отбросит). Но если надо сбросить посылку пожирнее, то внутри её получается каша, что логично.

Собственно, почему так происходит?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #1 : Январь 28, 2014, 10:05 »

Потому что данные от отправителя склеиваются сетевым стеком в один пакет, все согласно протокола.
Записан
ploop
Гость
« Ответ #2 : Январь 28, 2014, 10:13 »

Я всё понимаю, но тут другая ситуация. Отправляю данные один раз (вручную например), а получаю несколько копий.

Код
C++ (Qt)
void send_to_client()
{
 char buf[5] = {'1','2','3','4','5'};
 
 xxx++;
 qDebug() << xxx;
 
 socket->write(buf,5);
 socket->flush();
}

Лог отправляющей стороны:
Код:
debug:    [28.01.2014 11:09:29.256]: 1 
debug:    [28.01.2014 11:09:30.256]: 2
debug:    [28.01.2014 11:09:31.256]: 3
debug:    [28.01.2014 11:09:32.256]: 4
debug:    [28.01.2014 11:09:33.256]: 5
debug:    [28.01.2014 11:09:34.256]: 6
debug:    [28.01.2014 11:09:35.256]: 7
debug:    [28.01.2014 11:09:36.256]: 8

Принимающая сторона:

Код:
QTime("11:09:29") "12345" 
QTime("11:09:30") "12345"
QTime("11:09:31") "12345"
QTime("11:09:32") "12345"
QTime("11:09:33") "12345"
QTime("11:09:34") "12345"
QTime("11:09:35") "1234512345"
QTime("11:09:36") "1234512345"

Откуда 10 строк вместо восьми?

ЗЫ: Лог сделал только что, коннект - дисконнект, всё как есть.
« Последнее редактирование: Январь 28, 2014, 10:15 от ploop » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #3 : Январь 28, 2014, 10:31 »

Странная ситуация.
А точно отсылка через этот сокет происходит только в send_to_client? Может еще кто-то может это писать в слот?
Записан
ploop
Гость
« Ответ #4 : Январь 28, 2014, 10:39 »

Сокет сидит в отдельном потоке, сколько клиентов - столько потоков. Конструктор тоже проверял, создаётся один поток, один сокет. Вот код:
Код
C++ (Qt)
void serv::slot_new_connection()
{
 // QTcpServer* tcpserv если что
 QThread* thread = new QThread;
 ServerClient* serv_client = new ServerClient(
       tcpserv->nextPendingConnection(),
       &dbl,thread);
 
 serv_client->moveToThread(thread);
 
 connect(serv_client,SIGNAL(sig_stop(ServerClient*)),this,SLOT(slot_disconnected(ServerClient*))); // Тут поток уничтожается. Тоже корректно
 connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()));
 connect(thread,SIGNAL(finished()),serv_client,SLOT(deleteLater()));
 
 thread->start();
 
 qDebug() << "Client connected: id=" << (int)serv_client;
}
 

Внутри конструктора объекта:
Код
C++ (Qt)
 connect(socket,SIGNAL(readyRead()),this,SLOT(slot_read_client()));

Все тесты с одним клиентом. Если их несколько - ситуация аналогична, только с разными указателями на сокеты/потоки/объекты. То есть всё ровно.

Самое интересное - взял проект вчера домой, дабы спокойно поковыряться, и не смог воспроизвести ошибку, как ни старался! Всё работает чётко. Может что-нибудь связанное с системой быть? Порты разные пробовал...
Записан
ploop
Гость
« Ответ #5 : Январь 28, 2014, 10:43 »

Да тут просто по логике: если send_to_client вызовет кто-то ещё, увидим запись в логе.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #6 : Январь 28, 2014, 10:48 »

Да тут просто по логике: если send_to_client вызовет кто-то ещё, увидим запись в логе.
Ну кто-то может писать в сокет и не в этой функции имея на него указатель. Улыбающийся

Похоже, что у вас действительно проблемы не с программой, а с сетью.
Какая у вас платформа и как тестируете, через localhost или разные машины?
Записан
ploop
Гость
« Ответ #7 : Январь 28, 2014, 10:53 »

Да, через localhost
Ubuntu 12.04 (в системе чего только не понаставлено, но что может быть причиной не могу сообразить). Сборки будут и под Win32.
Наверное попробую собрать тестовый проект на другой машине...

Цитировать
Ну кто-то может писать в сокет и не в этой функции имея на него указатель
Прошерстил проект по ключевому слову "Write", ничего криминального Грустный
« Последнее редактирование: Январь 28, 2014, 10:57 от ploop » Записан
ploop
Гость
« Ответ #8 : Январь 28, 2014, 13:26 »

Кажется победил проблему.
Скомпилив на Windows и запустив, увидел ошибки в логе во время send_to_client:
Код:
QSocketNotifier: socket notifiers cannot be enabled from another thread
QSocketNotifier: socket notifiers cannot be disabled from another thread

И до меня дошло: сам объект находится в новом потоке, а сокет - в старом! Так как указатель на сокет я в конструктор передаю, просто добавил в конструктор это:
Код
C++ (Qt)
 socket->setParent(NULL);
 socket->moveToThread(thread_ptr()); // thread_ptr() просто возвращает указатель на поток.
 
// Ну и проверка в send_to_client
 if ((int)this->thread != (int)this->thread_ptr()) qDebug()<<"Self thread is bad";
 if ((int)this->thread != (int)socket->thread()) qDebug()<<"Socket thread is bad";
 
 

Вот этот тестовый код стал чётко работать. С реальными данными не знаю - весь код разворошил, буду в кучу собирать и пробовать Улыбающийся

----

Ну да, всё собрал. Мегабайтные куски друг за другом летают только в путь, и разбираются без ошибок.
Аккуратнее с потоками, господа Улыбающийся
« Последнее редактирование: Январь 28, 2014, 14:26 от ploop » Записан
OKTA
Гость
« Ответ #9 : Январь 30, 2014, 17:30 »

Не уж то наследовался от QThread??))
Записан
ploop
Гость
« Ответ #10 : Январь 30, 2014, 19:06 »

Нет, зачем?
Весь код я привёл выше. Собственно, это всё.
Сегодня проверили сервер с несколькими десятками клиентов и большой нагрузкой на сеть (при чём некоторые клиенты на плохом соединении) - нормально всё, падений нет, утечек, по мнению Valgrind, - тоже.
Записан
vulko
Гость
« Ответ #11 : Март 03, 2014, 09:05 »

У меня похожая непонятка. Отправляю через сокет 128 байт, получаю, закрываю, запрашиваю снова, получаю и т.д.

Однако иногда приходит пакет 4224 байт, хз откуда берущийся...
Записан
OKTA
Гость
« Ответ #12 : Март 03, 2014, 09:14 »

а что в пакете-то?))
Записан
vulko
Гость
« Ответ #13 : Март 03, 2014, 09:23 »

а что в пакете-то?))

у меня? сериализованный данные. массив из 8 элементов структуры, состоящей из 1 инта и 3х флоутов. 8 элементов по 16 байт, итого 128 байт.

откуда 4224 байта вообще хз...
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


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

Как вариант - 33 ваших пакета.  Подмигивающий
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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