Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
45 / 25 / 16
Регистрация: 14.04.2011
Сообщений: 623

Клиент-серверная рисовалка, найти ошибку в коде

05.08.2014, 19:13. Показов 1477. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Решил попробовать написать обычную "рисовалку".
Принцип прост: 1 человек водит мышкой по форме и у всех рисуется.
В итоге написал так, что если рисовать очень медленно, то у того кто рисует все в порядке, а у других иногда лишь точки появляются...
Если рисовать как обычно, то на серверной стороне в 1 принятом сообщение несколько десятков разных сообщений.
В итоге сервер это просто игнорирует и рисунок получается в "крапинку" и опять же у всех других вообще не рисует или рисует просто точку...

Как исправить?
Если тестировать это через "127.0.0.1", то более менее рисует нормально, если тестировать через внешний IP то как я описывал выше...
Вложения
Тип файла: rar painter.rar (45.9 Кб, 23 просмотров)
Тип файла: rar socket_server.rar (36.3 Кб, 22 просмотров)
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
05.08.2014, 19:13
Ответы с готовыми решениями:

Найти ошибку в коде
помогите кто может, написал прогу, а ругается на moveto и т.п. переделайте что не так пожалуйста и скиньте файлом архивом, просто срочно...

Найти ошибку в коде
Задание состоит в том, что нужно найти ошибку в коде. Я этот код проверил вдоль и поперек чуть ли не под лупой просматривал. Не вижу...

Помогите найти ошибку в коде
Подскажите где ошибка void __fastcall TForm1::sButton1Click(TObject *Sender) { int i,f,k; float s=0; ...

17
45 / 25 / 16
Регистрация: 14.04.2011
Сообщений: 623
05.08.2014, 19:13  [ТС]
Билдер XE6
0
 Аватар для DeadHipo
85 / 85 / 33
Регистрация: 21.09.2013
Сообщений: 339
05.08.2014, 19:31
К сожалению я не особо селён в этой теме, но
Цитата Сообщение от Путин Посмотреть сообщение
Если тестировать это через "127.0.0.1", то более менее рисует нормально, если тестировать через внешний IP то как я описывал выше...
вот это можно объяснить скоростью передачи. И думаю тебе стоит передавать через каждый определённый промежуток массив точек, а не каждую (как я могу предположить, у тебя и сделано)
1
45 / 25 / 16
Регистрация: 14.04.2011
Сообщений: 623
05.08.2014, 21:52  [ТС]
DeadHipo, Ну да, у меня передача координат стоит в событие "MouseMove"
0
 Аватар для DeadHipo
85 / 85 / 33
Регистрация: 21.09.2013
Сообщений: 339
05.08.2014, 22:18
Путин, ну так это событие вызываться каждый раз когда изменяется X Y, а при рисовании это очень часто. Так что думаю передача 10 - 20 значений в массиве решит твою проблему.
0
45 / 25 / 16
Регистрация: 14.04.2011
Сообщений: 623
06.08.2014, 00:50  [ТС]
Попробовал записывать TStringList
C++
1
2
3
4
5
6
7
8
9
10
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
{
    if (can == true) // Mouse Down ?
    {
        if (connected == true)
        {
            s->Add("{\"left\":"+IntToStr(X)+", \"top\":"+IntToStr(Y)+", \"width\":"+this->__W__+"}\n"); //width = толщина кисти 
        }
    }
}
и по таймеру передавать данные
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
    WideString buff;
    for (int i = 0; i < s->Count; i++)
    {
        if (s->operator [](i).IsEmpty())    continue;
        buff += s->operator [](i)+"\n";
        s->Delete(i);
    }
    if (connected && buff.IsEmpty() == false)
        this->Sock->Socket->SendText(buff);
    buff = "";
}
вроде записывает и передает, но получилось еще хуже, теперь даже в 127.0.0.1 все крапинку. Не получается что-то сделать

Добавлено через 1 минуту
Ну и принимаю от сервера кашу:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void __fastcall TForm1::SockRead(TObject *Sender, TCustomWinSocket *Socket)
{
    WideString msg = Socket->ReceiveText();
    if (msg.IsEmpty())  return;
    int _X__;
    int _Y__;
    int _W__;
    bes->Delimiter = '\n';
    bes->StrictDelimiter = true;
    bes->DelimitedText = msg;
    for (int i = 0; i < bes->Count; i++)
    {
        TJSONObject *jObj = static_cast<TJSONObject*>(TJSONObject::ParseJSONValue(bes->operator [](i)));
        if (jObj->Get("left")->JsonValue->Value() == "CLEAR")   {InvalidateRect ( this->Handle, NULL, True );continue;}
        _X__ = StrToInt(jObj->Get("left")->JsonValue->Value());
        _Y__ = StrToInt(jObj->Get("top")->JsonValue->Value());
        _W__ = StrToInt(jObj->Get("width")->JsonValue->Value());
        this->Label3->Caption = "Онлайн: "+jObj->Get("online")->JsonValue->Value();
        delete jObj;
 
        this->Canvas->Pen->Width = _W__;
        this->Canvas->Pen->Color = clGreen;
        this->Canvas->MoveTo(_X__,_Y__);
        this->Canvas->LineTo(_X__,_Y__);
        bes->Delete(i);
    }
}
Добавлено через 1 минуту
В итоге частенько в цикле появляются какието фатальные ошибки, под дебагом даже не показывает строку с ошибкой

Добавлено через 2 минуты
И наверное это из за того, что в конце передаваемой каши стоит "\n" и он пошел получать координаты из пустой строки...

Добавлено через 1 минуту
Даже с таким "буфером" четкость линии зависит от интервала таймер (чем меньше интервал, тем четче рисует), как так получилось, я же вроде записал все в буфер...
0
 Аватар для DeadHipo
85 / 85 / 33
Регистрация: 21.09.2013
Сообщений: 339
06.08.2014, 01:36
Так дело не пойдёт. Есть у меня подозрения,что удаляя i строку ты в последствии поместишь в неё новые значения пока таймер не обработает всё полностью и в итоге всё запутается.
Стоит сделать всё в событии мышки.
Например пока count твоего стриг листа не равен 10 записывать в него, а как он будет больше то передать значения значения. И вообще передачу запихнуть в поток.
Т.е. Проверка на кол-во записей
Если больше то передаём данные из нашего стринг листа в поток и отправляем, а в это время чистим стринглист и уже пишем новые значения.

Добавлено через 7 минут
И всё же не торопись писать, то что я тебе описал. Лучше подождать советов более умных и профессиональных людей, так как я руководствуюсь только логикой
0
Почетный модератор
Эксперт С++
 Аватар для SatanaXIII
5851 / 2862 / 392
Регистрация: 01.11.2011
Сообщений: 6,906
06.08.2014, 09:01
Путин, все вам правильно DeadHipo начинал советовать:
Заведите себе поток (таймер), в котором раз в определенный интервал (зависящий от ширины канала) берите все изображение, суйте его в битмап, который уже и отсылайте.
В итоге приложение будет раз в интервал копировать изображение в поток, который уже будет все и отсылать.
Модификация 1: А, к примеру, после завершения отправки взводить какой-нибудь флаг. И если событие таймера наступило, а флаг не взведен, то не отправлять новое изображение, а ждать отправки старого.
Модификация 2: Перед отправкой к битмапу можно применить какое-либо архивирование. Для ускорения передачи.
0
 Аватар для DeadHipo
85 / 85 / 33
Регистрация: 21.09.2013
Сообщений: 339
06.08.2014, 11:14
SatanaXIII, такой вариант тоже можно, просто мне кажется вся задумка автора пропадёт. Я о по точечной отрисовке
0
Почетный модератор
Эксперт С++
 Аватар для SatanaXIII
5851 / 2862 / 392
Регистрация: 01.11.2011
Сообщений: 6,906
06.08.2014, 11:36
Цитата Сообщение от DeadHipo Посмотреть сообщение
Я о по точечной отрисовке
Эта задумка приведет автора прямо в ад. Можно и ргб на каждый пиксель тремя переменными пересылать, чего уж там.
0
74 / 54 / 17
Регистрация: 10.07.2014
Сообщений: 329
06.08.2014, 13:39
SatanaXIII,
А если канал узкий? пересылать к примеру 1920х1080х4 (это для BMP) - 8294400 байт...
Любой канал ляжет.

Путин, общая идея действительно такова:
На стороне клиента в MouseMove если рисуем (нажата клавиша) генерим в какую-то очередь событие, поменьше. например
(тип=точка,цвет,Х,У)
потом на будущее события разные могут быть, типа
(тип=круг, цвет,Х,У,Радиус)
Складываем эти события в контейнер.
В паралельном потоке, отсылаем данные из контейнера.
В еще одном паралельном потоке принимаем данные от сервера и отрисовываем в клиенте
0
 Аватар для DeadHipo
85 / 85 / 33
Регистрация: 21.09.2013
Сообщений: 339
06.08.2014, 14:01
krv, думаю ещё необходимо принимать положение X Y относительно краёв Image или чего то другого, а не формы , и при начале передачи указать размеры контейнера в котором рисуется изо.

Добавлено через 1 минуту
Прощу прощения на форме рисуем, на форме отображаем...
0
Почетный модератор
Эксперт С++
 Аватар для SatanaXIII
5851 / 2862 / 392
Регистрация: 01.11.2011
Сообщений: 6,906
06.08.2014, 14:02
Цитата Сообщение от krv Посмотреть сообщение
к примеру 1920х1080х4 (это для BMP) - 8294400 байт
Факт.
Цитата Сообщение от krv Посмотреть сообщение
генерим в какую-то очередь событие
В момент нажатия кнопки мышки цвет, ширина кисти, все дела известны. Можно, к примеру, запоминать только координаты пикселей над которыми прошла мышка до отжатия кнопки. И либо создавать опять же катру-бинарную матрицу, либо последовательность пар-координат, из которых потом выкинуть дубли. И вот эту хрень уже передавать, снабдив заголовком с информацией о кисти.
На клиенте тупо перерисовывать.

И каждую такую серию нажатий/отжатий ставить в очередь на отсылку. Гарантировать, чтобы все передалось, даже, если будет тормозить что.
1
45 / 25 / 16
Регистрация: 14.04.2011
Сообщений: 623
06.08.2014, 18:47  [ТС]
Цитата Сообщение от SatanaXIII Посмотреть сообщение
В момент нажатия кнопки мышки цвет, ширина кисти, все дела известны. Можно, к примеру, запоминать только координаты пикселей над которыми прошла мышка до отжатия кнопки. И либо создавать опять же катру-бинарную матрицу, либо последовательность пар-координат, из которых потом выкинуть дубли. И вот эту хрень уже передавать, снабдив заголовком с информацией о кисти.
На клиенте тупо перерисовывать.
И каждую такую серию нажатий/отжатий ставить в очередь на отсылку. Гарантировать, чтобы все передалось, даже, если будет тормозить что.
Походу я никогда не закончу эту идею, ну хоть подобие получилось
0
Почетный модератор
Эксперт С++
 Аватар для SatanaXIII
5851 / 2862 / 392
Регистрация: 01.11.2011
Сообщений: 6,906
07.08.2014, 08:48
Путин, ну что вы блин. К примеру:
Цитата Сообщение от SatanaXIII Посмотреть сообщение
последовательность пар-координат
Здесь, участвуют три события:
1) OnMouseDown - в нем просто выставляется флаг нажатия кнопки. Начало сессии записи.
2) OnMouseMove - заполняется вектор (или стек, типа того), первый элемент которого это пара координат точки нажатия мыши. При движении мыши все точки, над которыми она проходит записываются в вектор.
3) OnMouseUp - запись прекращается; убирается флаг, выставленный в MouseDown. Записанный вектор проверяется на одинаковые элементы, которые выкидываются (чтобы меньше передавать). Готовый вектор копируется в пересылающий поток.

P.S. В потоке можно реализовать простую очередь векторов. Цикл: как только передача очередного вектора закончена, идет проверка - есть ли еще вектора в очереди. Пока очередь не пуста передавать. Соответственно, при получении нового вектора записывать его в конец очереди.
1
07.08.2014, 22:29

Не по теме:

Еще вчера хотел написать эту штуку, но не нашел в себе сил, простымши...:sleep: Путин, ты, главно, не сдавайся раньше времени - помощники подтянутся.

0
45 / 25 / 16
Регистрация: 14.04.2011
Сообщений: 623
10.08.2014, 23:38  [ТС]
может быть, в далеком будущем я таки допишу эту идею, а сейчас банально не хватает знаний, учу С++ исключительно практикой (в прочем как и любой другой язык)
0
45 / 25 / 16
Регистрация: 14.04.2011
Сообщений: 623
08.09.2014, 11:19  [ТС]
помогла опция отключения nagle режима и стало рисовать в разы лучше...
C++
1
2
char *value = "1";
setsockopt( this->Sock->Socket->SocketHandle, IPPROTO_TCP, TCP_NODELAY, value, sizeof(value) );
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
08.09.2014, 11:19
Помогаю со студенческими работами здесь

RegExp - найти ошибку в коде
Привет всем:) void __fastcall TForm1::Button7Click(TObject *Sender) { TStringList* List=new TStringList; TRegExpr* RegExp=new...

Builder C++; не могу найти ошибку в коде
#include &lt;iostream.h&gt; #include &lt;stdlib.h&gt; #include &lt;conio.h&gt; // описание шаблона класса template &lt;class Qtype&gt; class queue { ...

Помогите найти ошибку в программном коде
/* MP3 плеер с регулятором громкости. Демонстрирует работу с компонентом MediaPlayer. Картинки для кнопки Play/Stop...

Помогите пожалуйста найти ошибку в коде
Уплотнить матрицу, удаляя из нее строки и столбцы, заполненные нулями. #include &lt;iostream.h&gt; #include &lt;conio.h&gt; #include...

Клиент-серверная БД
Доброго времени суток. Разрабатываю клиент-серверную СУБД. Сама БД хранится в файле *.mdb, Серверная часть подключается к файлу с помощью...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru