Архив: Технология создания плагинов
Re: Технология создания плагинов
Ну все равно, то через раз, то 5 мин (блин я то думаю, че за хрень я указал единицу а забанило на 5 минут)
-
- Сообщения: 109
- Зарегистрирован: 08:23, 11.12.2008
- Откуда: Комсомольск-на-Амуре
- Контактная информация:
Re: Технология создания плагинов
Пожалуйста, помогите разобраться, срочно надо!
2 потока.
1 поток (основной)
- PluginStart(...)
- PluginStop()
- PluginProcess(...)
- PluginGetData(...)
2 поток (создается в PluginStart)
- бесконечный while(1)
Теперь представим ситуацию.
Во втором потоке в цикле в определенный момент времени произойдет вызов (*CommFortProcess)(...), в этот же момент произойдет событие в чате и вызовется функция PluginProcess(...) в первом потоке. Т.к. выполнение (*CommFortProcess)(...) не успевает завершится - зависает сервер комфорта (может быть наоборот, в момент работы функции PluginProcess(...) вызывается во втором потоке (*CommFortProcess)(...)).
Как решить эту проблему? Поместить в 1 поток бесконечный цикл нельзя, отказаться от него нельзя, оконные сообщения не подходят ибо и окна нет и в первом потоке останавливаться нельзя... Организовывать очередь для функции и выполнять события из очереди первым потоком слишком ресурсозатратно...
2 потока.
1 поток (основной)
- PluginStart(...)
- PluginStop()
- PluginProcess(...)
- PluginGetData(...)
2 поток (создается в PluginStart)
- бесконечный while(1)
Теперь представим ситуацию.
Во втором потоке в цикле в определенный момент времени произойдет вызов (*CommFortProcess)(...), в этот же момент произойдет событие в чате и вызовется функция PluginProcess(...) в первом потоке. Т.к. выполнение (*CommFortProcess)(...) не успевает завершится - зависает сервер комфорта (может быть наоборот, в момент работы функции PluginProcess(...) вызывается во втором потоке (*CommFortProcess)(...)).
Как решить эту проблему? Поместить в 1 поток бесконечный цикл нельзя, отказаться от него нельзя, оконные сообщения не подходят ибо и окна нет и в первом потоке останавливаться нельзя... Организовывать очередь для функции и выполнять события из очереди первым потоком слишком ресурсозатратно...
Забросил, всем спасибо, исходники раздаю кому надо https://github.com/ZigZagkms
Re: Технология создания плагинов
ZigZagkms, так как ты явно не используешь синхронизацию процессов (да и в dll она практически не возможна), то работая с двумя потоками функция PluginProcess, вызванная в обеих потоках в одно и тоже время, выполняется параллельно. А это уже получается как "обезьяна с гранатой": неизвестно в какое время произойдет сбой. Так что в таких случаях надо внимательно следить за целостностью данных: использовать только локальные переменные функции или сделать очередь. Самый простой способ создания очереди - используешь переменную-флаг для определения: закончилось ли выполнение предыдущей копии функции или нет. Если закончилось - выполняешь новую копию, если нет, то ждешь пока флаг не будет обозначать, что выполнение закончилось.
А вообще я тоже использую многопоточность и у меня таких проблем не возникало...
Maxim Mirgorodsky, а что на счет дебага плагинов? Может все-таки сделаете какую-то урезанную версию для разрабов, без Themida'ы? А то трудновато дебажить
А вообще я тоже использую многопоточность и у меня таких проблем не возникало...
Maxim Mirgorodsky, а что на счет дебага плагинов? Может все-таки сделаете какую-то урезанную версию для разрабов, без Themida'ы? А то трудновато дебажить

Блин, а я то думаю - почему какое бы время не ставлю, все равно 5 минут)))...KGB писал(а):У меня на триальной версии банит нормально. Ограничение только в сроке бана (всегда 5 мин).
-
- Сообщения: 109
- Зарегистрирован: 08:23, 11.12.2008
- Откуда: Комсомольск-на-Амуре
- Контактная информация:
Re: Технология создания плагинов
Во втором потоке я не использую функцию PluginProcess, во втором потоке вызывается импортируемая функция CommFortProcess. Сервер сам вызывает PluginProcess, как только происходит какое либо событие в чате. Не правильно ты понял суть моего вопроса. Про проблемы с синхронизацией знаю, где надо использую критические секции, но в данном случае не нашел способа тут это применить, это надо применять в самом сервере, чтобы он не вызывал функцию PluginProcess пока отрабатывает импортируемая функция (*CommFortProcess).$teelR@t писал(а):ZigZagkms, так как ты явно не используешь синхронизацию процессов (да и в dll она практически не возможна), то работая с двумя потоками функция PluginProcess, вызванная в обеих потоках в одно и тоже время, выполняется параллельно. А это уже получается как "обезьяна с гранатой": неизвестно в какое время произойдет сбой. Так что в таких случаях надо внимательно следить за целостностью данных: использовать только локальные переменные функции или сделать очередь. Самый простой способ создания очереди - используешь переменную-флаг для определения: закончилось ли выполнение предыдущей копии функции или нет. Если закончилось - выполняешь новую копию, если нет, то ждешь пока флаг не будет обозначать, что выполнение закончилось.
А вообще я тоже использую многопоточность и у меня таких проблем не возникало...
Плагин работает на сервере где онлайн достигает 2000 пользователей, события возникают ежесекундно, и то проблема за трое суток выявила себя 2 раза, когда более менее нагрузку дал на функцию (*CommFortProcess).. (передал картинку, пока функция отрабатывала свое, а это миллисекунды, возникло событие в чате, вероятность мала, но все же присутствует, произошло зависание...)
Забросил, всем спасибо, исходники раздаю кому надо https://github.com/ZigZagkms
Re: Технология создания плагинов
ZigZagkms, тогда у тебя получается, что вся обработка событий от сервера выполняется в одном потоке, а судя по тому, что сервер и плагин работают в одном потоке, то в теории события должны выполняться по очереди. Значит проблемы на стороне сервера, он просто не справляется с нагрузкой...
-
- Сообщения: 109
- Зарегистрирован: 08:23, 11.12.2008
- Откуда: Комсомольск-на-Амуре
- Контактная информация:
Re: Технология создания плагинов
Нет, дело не в этом, даже если в функции PluginProcess нету обработки событий вообще все равно виснет, проблема не в этом.$teelR@t писал(а):ZigZagkms, тогда у тебя получается, что вся обработка событий от сервера выполняется в одном потоке, а судя по тому, что сервер и плагин работают в одном потоке, то в теории события должны выполняться по очереди. Значит проблемы на стороне сервера, он просто не справляется с нагрузкой...
Забросил, всем спасибо, исходники раздаю кому надо https://github.com/ZigZagkms
-
- Администратор
- Сообщения: 6890
- Зарегистрирован: 09:56, 27.06.2005
Re: Технология создания плагинов
В случае подачи некорректных данных программа не зависнет.ZigZagkms писал(а):Вопрос к Maxim Mirgorodsky.
Скажите пожалуйста, как происходит фильтрация поступающих данных, полная или частичная, допустим если мы подадим в функцию неверную инфу как ее обрабатывает сервер?
Например, я посылаю серверу событие с ID 1001, а заместо блока данных подаю 4 байта (FF FF FF FF) (т.е. создаю ошибку, предоставляю ложную длину текста, причем невозможную) - плагин останавливается. Т.е. он словил исключение о невозможности прочитать данные или как там работает этот механизм?
Мне необходимо знать возможны ли зависания сервера при подачи неверного блока данных (с любым ID), например как должен повести себя сервер если я ему подам картинку размером правильным, а пикселей будет больше, и прочие подобные тонкости, дело в том что возникают проблемы, а где возникают не понятно, вот возникла такая мысль что возможно в этом, фильтровать самому каждый передающий параметр затратно если это уже делает сам сервер.
Было бы здорово если бы сервер просто игнорировал все ошибочные данные, не останавливая плагин..
С Вашим случаем разобрались по ЛС, причина в некорректно реализованной многопоточности.
Программа проверяет данные на соответствие объему. В случае несоответствия разумеется нормальная работа плагина не будет возможной, но на работу программы это не повлияет.@serg@ писал(а):Коммфорт не может проверить FF FF FF FF это ошибка или действительно имя такой длинны, поэтому пытается прочитать все данные, при этом происходит ошибка прав доступа, идёт чтение ложных данных, и при попытке обработать естественно вызывается ошибка, которую тупо проигнорировать опасно. В этом случае лучше передавать в плане длинны заведомо корректные значения (что не так сложно), и следить внимательно за соблюдением порядка данных (что намного сложней), в этом случае коммфорту придётся отслеживать только корректность текста.ZigZagkms писал(а):Вопрос к Maxim Mirgorodsky.
Скажите пожалуйста, как происходит фильтрация поступающих данных, полная или частичная, допустим если мы подадим в функцию неверную инфу как ее обрабатывает сервер?
Например, я посылаю серверу событие с ID 1001, а заместо блока данных подаю 4 байта (FF FF FF FF) (т.е. создаю ошибку, предоставляю ложную длину текста, причем невозможную) - плагин останавливается. Т.е. он словил исключение о невозможности прочитать данные или как там работает этот механизм?
Мне необходимо знать возможны ли зависания сервера при подачи неверного блока данных (с любым ID), например как должен повести себя сервер если я ему подам картинку размером правильным, а пикселей будет больше, и прочие подобные тонкости, дело в том что возникают проблемы, а где возникают не понятно, вот возникла такая мысль что возможно в этом, фильтровать самому каждый передающий параметр затратно если это уже делает сам сервер.
Было бы здорово если бы сервер просто игнорировал все ошибочные данные, не останавливая плагин..
Но более точно тебе ответит естественно Maxim.
-
- Сообщения: 109
- Зарегистрирован: 08:23, 11.12.2008
- Откуда: Комсомольск-на-Амуре
- Контактная информация:
Re: Технология создания плагинов
Максим, здравствуйте.
Сообщение было опубликовано после обращения в приват, мне не удалось решить проблему самому решил спросить совета у всех как это можно сделать. Синхронизации не помогают (ткните пальцев как их применить в моей проблеме возьму свои слова назад и скажу большое спасибо), один выход из проблемы - использовать импортируемую функцию только в главном потоке CommFortProcess (как Вы и сказали что ее можно использовать только в главном потоке), я подумал создать очередь запросов к функции которая наполняется вторым потоком, НО главный вопрос как обслуживать (выталкивать и исполнять) эту очередь в первом потоке? Ведь WaitObject подобные функции мы использовать не можем, зависания в главном потоке недопустимы... Тоже самое кстати относится и ко второй импортируемой функции, тут очередь сложно применима, т.к. необходимо еще и получать результаты выполнения.
Проблема остается открытой, советов от участников конференции кроме как "у меня и так работает" не было получено. Помогите пожалуйста разобраться и я отстану!)
Хорошо, вот код для понимания моей проблемы
Поток 1:
Поток 2:
И вот, если в первом произойдет событие и не успев отработаться "// Что угодно" выполнится во втором (*CommFortProcess) произойдет зависание. Вариант два, с синхронизацией (единственное что я смог придумать, реализация не верная, в этом случае зависания происходят либо как в первом варианте либо зависает плаг)
Поток 1:
Поток 2:
Как помоему то проблему можно решить добавлением критических секций в исходном коде самого сервера, не выполнять вызов функции, и исчезнет проблема с использованием импортируемых функций в потоках. I need help! 
Сообщение было опубликовано после обращения в приват, мне не удалось решить проблему самому решил спросить совета у всех как это можно сделать. Синхронизации не помогают (ткните пальцев как их применить в моей проблеме возьму свои слова назад и скажу большое спасибо), один выход из проблемы - использовать импортируемую функцию только в главном потоке CommFortProcess (как Вы и сказали что ее можно использовать только в главном потоке), я подумал создать очередь запросов к функции которая наполняется вторым потоком, НО главный вопрос как обслуживать (выталкивать и исполнять) эту очередь в первом потоке? Ведь WaitObject подобные функции мы использовать не можем, зависания в главном потоке недопустимы... Тоже самое кстати относится и ко второй импортируемой функции, тут очередь сложно применима, т.к. необходимо еще и получать результаты выполнения.
Проблема остается открытой, советов от участников конференции кроме как "у меня и так работает" не было получено. Помогите пожалуйста разобраться и я отстану!)
Хорошо, вот код для понимания моей проблемы
Поток 1:
Код: Выделить всё
// Прием событий
VOID PluginProcess(DWORD dwID, BYTE * bInBuffer, DWORD dwInBufferSize)
{
// Что угодно
}
Код: Выделить всё
DWORD WINAPI fNetThread(LPVOID lpParam)
{
while (true)
{
// Замираем на 200ms
Sleep(200)
// Произошло какое то внешнее событие
if (nowdo)
{
(*CommFortProcess)(dwPluginID, dwID, data, data_len);
}
}
}
Поток 1:
Код: Выделить всё
// Прием событий
VOID PluginProcess(DWORD dwID, BYTE * bInBuffer, DWORD dwInBufferSize)
{
EnterCriticalSection(&cs);
// Что угодно
LeaveCriticalSection(&cs);
}
Код: Выделить всё
DWORD WINAPI fNetThread(LPVOID lpParam)
{
while (true)
{
// Замираем на 200ms
Sleep(200)
// Произошло какое то внешнее событие
if (nowdo)
{
EnterCriticalSection(&cs);
(*CommFortProcess)(dwPluginID, dwID, data, data_len);
LeaveCriticalSection(&cs);
}
}
}

Забросил, всем спасибо, исходники раздаю кому надо https://github.com/ZigZagkms
-
- Сообщения: 659
- Зарегистрирован: 08:54, 13.07.2010
- Откуда: Чебоксары, Россия
- Контактная информация:
Re: Технология создания плагинов
Предложу один вариант, хотя он может быть и неверным. Заполнение и вытаскивание элементов из очереди - критические секции (это и так понятно). Можно воспользоваться таймером, созданным в основном потоке (интервал - 1мс). При инициализации отключаем его (Enabled = False). Последним действием при добавлении элемента в очередь - включаем. При обработке события OnTimer - вытаскивание элемента, если очередь не пуста или отключение таймера, если она пуста.ZigZagkms писал(а):Максим, здравствуйте.
один выход из проблемы - использовать импортируемую функцию только в главном потоке CommFortProcess (как Вы и сказали что ее можно использовать только в главном потоке), я подумал создать очередь запросов к функции которая наполняется вторым потоком, НО главный вопрос как обслуживать (выталкивать и исполнять) эту очередь в первом потоке?
Время ожидания добавления элемента в очередь мне кажется не особо критичным в этом случае.
Если неправ, просьба не бить, только учусь

-
- Сообщения: 109
- Зарегистрирован: 08:23, 11.12.2008
- Откуда: Комсомольск-на-Амуре
- Контактная информация:
Re: Технология создания плагинов
Формы у меня в проекте нету. Насколько мне известно таймер он посылает сообщение окну WM_TIMER и тогда уже выполняется функция, была бы форма было бы проще посылать сообщения самому со своим идентификатором и выполнять, хотя в этом я тоже могу ошибаться, не долго я с С++ работаю, как раз с тех самых пор когда разработчики отказались от UDP=) Добавлять форму ради таймера не охота, слишком большие затраты.KGB писал(а):Предложу один вариант, хотя он может быть и неверным. Заполнение и вытаскивание элементов из очереди - критические секции (это и так понятно). Можно воспользоваться таймером, созданным в основном потоке (интервал - 1мс). При инициализации отключаем его (Enabled = False). Последним действием при добавлении элемента в очередь - включаем. При обработке события OnTimer - вытаскивание элемента, если очередь не пуста или отключение таймера, если она пуста.
Время ожидания добавления элемента в очередь мне кажется не особо критичным в этом случае.
Если неправ, просьба не бить, только учусь
Забросил, всем спасибо, исходники раздаю кому надо https://github.com/ZigZagkms
-
- Сообщения: 659
- Зарегистрирован: 08:54, 13.07.2010
- Откуда: Чебоксары, Россия
- Контактная информация:
Re: Технология создания плагинов
Создавать таймер можно и в процессе выполнения, в том числе без родительской формы. От сообщений, конечно, никуда не деться, но в этом случае таймер создаёт собственное окно. И затраты будут только на него (вот тут уже я могу ошибаться).ZigZagkms писал(а): Формы у меня в проекте нету. Насколько мне известно таймер он посылает сообщение окну WM_TIMER и тогда уже выполняется функция, была бы форма было бы проще посылать сообщения самому со своим идентификатором и выполнять, хотя в этом я тоже могу ошибаться, не долго я с С++ работаю, как раз с тех самых пор когда разработчики отказались от UDP=) Добавлять форму ради таймера не охота, слишком большие затраты.
Re: Технология создания плагинов
Блин. Ёлки-палки, лес дремучий.@serg@ писал(а):Код: Выделить всё
AnsiString aData;//буфер int iSize = (*CommFortGetData)(12, dwID, NULL, NULL, NULL, NULL); //получаем объем буфера aData.SetLength(iSize); (*CommFortGetData)(12, dwID,aData.c_str(),iSize, NULL, NULL);//заполняем буфер int rOffset=0; fReadText(aData.c_str(),&rOffset);//тут имя твоего пользователя
var aData : AnsiString;
iSize:=CommFortGetData(12, 0, 0, 0, 0);
SetLength(aData, iSize);
CommFortGetData(12, aData, iSize, 0, 0);
fReadText(aData, iOffset);
Ему не нравится aData. Вот что пишет:
Вот сама функция:[Error] main.pas(339): Incompatible types: 'String' and 'PAnsiChar'
[Error] main.pas(340): Incompatible types: 'String' and 'PAnsiChar'
TCommFortGetData = function(dwID : DWORD; bInBuffer : PAnsiChar; dwInBufferSize : DWORD; bOutBuffer : PAnsiChar; dwOutBufferSize : DWORD): DWORD; stdcall;
Что-то с этим aData. Беда. Ну ясен пень, надо его в PAnsiChar загнать. Ведь так? Или что я не так делаю?
Дайте мне ещё слова напутствия, пожалуйста (:
http://mediumeex.livejournal.com
Re: Технология создания плагинов
С дельфи не проконсультирую, ошибка точно в первом вызове. Тут во втором параметре должен быть ID плагина. fReadText, это пример функции, который был в NULL-плагине, на начальном этапе я не стал её переделывать.Aarts писал(а): iSize:=CommFortGetData(12, 0, 0, 0, 0);
SetLength(aData, iSize);
CommFortGetData(12, aData, iSize, 0, 0);
fReadText(aData, iOffset);
Код: Выделить всё
UnicodeString fReadText(BYTE * bInBuffer, int * iOffset)
{//вспомогательная функция для упрощения чтениея Unicod
int iLength;
memcpy(&iLength, bInBuffer + (*iOffset),4);
(*iOffset)+=4;
UnicodeString uRet;
uRet.SetLength(iLength);
memcpy(uRet.c_str(), bInBuffer + (*iOffset),iLength*2);
(*iOffset)+=iLength*2;
return uRet;
}
Re: Технология создания плагинов
Вопрос ко всем, в том числе и к самому Максиму:Maxim Mirgorodsky писал(а): Изменения по системе плагинов в сервере 5.03:
...
- Исправлена ошибка при получении данных от программы с ID=1080;
...
проверял ли кто работу получения данных от программы с ID=1080? или я что-то не так делаю, либо действительно приходят неверные данные.
UPD: однажды получилось правильно написать процедуру получения списка, но потом опять всё свалилось... печалька. дайте код на С++
UPD2:
Код: Выделить всё
int size = VirtualUser.Length() * 2 + 4;
int len = VirtualUser.Length() * 2;
BYTE * bOutBuffer = new BYTE[size];
memcpy(bOutBuffer, &len, 4);
memcpy(bOutBuffer + 4, VirtualUser.c_str(), len * 2);
int dwInBufferSize = (*CommFortGetData)(dwPluginID, 1080, 0, 0, bOutBuffer, size);
BYTE * bInBuffer = new BYTE[dwInBufferSize];
(*CommFortGetData)(dwPluginID, 1080, bInBuffer, dwInBufferSize, bOutBuffer, size);
int countChannels;
memcpy(&countChannels, bInBuffer, 4);
UPD3:
Каковы должны быть условия для правильно работы? Может быть, уже подключенный виртуальный пользователь или еще что-то? И эта функция вообще работает на триальных версиях сервера?
Последний раз редактировалось ОреЛ 16:09, 19.11.2010, всего редактировалось 3 раза.
Когда пишете программу, всегда думайте о том, что её может затем поддерживать психопат и насильник, который знает где вы живёте.
— Martin Golding
— Martin Golding
-
- Сообщения: 659
- Зарегистрирован: 08:54, 13.07.2010
- Откуда: Чебоксары, Россия
- Контактная информация:
Re: Технология создания плагинов
В 5.00 не работала, в 5.03 работает, проверял.