Re: Технология создания плагинов
Добавлено: 23:20, 13.11.2010
Ну все равно, то через раз, то 5 мин (блин я то думаю, че за хрень я указал единицу а забанило на 5 минут)
Блин, а я то думаю - почему какое бы время не ставлю, все равно 5 минут)))...KGB писал(а):У меня на триальной версии банит нормально. Ограничение только в сроке бана (всегда 5 мин).
Во втором потоке я не использую функцию PluginProcess, во втором потоке вызывается импортируемая функция CommFortProcess. Сервер сам вызывает PluginProcess, как только происходит какое либо событие в чате. Не правильно ты понял суть моего вопроса. Про проблемы с синхронизацией знаю, где надо использую критические секции, но в данном случае не нашел способа тут это применить, это надо применять в самом сервере, чтобы он не вызывал функцию PluginProcess пока отрабатывает импортируемая функция (*CommFortProcess).$teelR@t писал(а):ZigZagkms, так как ты явно не используешь синхронизацию процессов (да и в dll она практически не возможна), то работая с двумя потоками функция PluginProcess, вызванная в обеих потоках в одно и тоже время, выполняется параллельно. А это уже получается как "обезьяна с гранатой": неизвестно в какое время произойдет сбой. Так что в таких случаях надо внимательно следить за целостностью данных: использовать только локальные переменные функции или сделать очередь. Самый простой способ создания очереди - используешь переменную-флаг для определения: закончилось ли выполнение предыдущей копии функции или нет. Если закончилось - выполняешь новую копию, если нет, то ждешь пока флаг не будет обозначать, что выполнение закончилось.
А вообще я тоже использую многопоточность и у меня таких проблем не возникало...
Нет, дело не в этом, даже если в функции PluginProcess нету обработки событий вообще все равно виснет, проблема не в этом.$teelR@t писал(а):ZigZagkms, тогда у тебя получается, что вся обработка событий от сервера выполняется в одном потоке, а судя по тому, что сервер и плагин работают в одном потоке, то в теории события должны выполняться по очереди. Значит проблемы на стороне сервера, он просто не справляется с нагрузкой...
В случае подачи некорректных данных программа не зависнет.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.
Код: Выделить всё
// Прием событий
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);
}
}
}
Код: Выделить всё
// Прием событий
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);
}
}
}
Предложу один вариант, хотя он может быть и неверным. Заполнение и вытаскивание элементов из очереди - критические секции (это и так понятно). Можно воспользоваться таймером, созданным в основном потоке (интервал - 1мс). При инициализации отключаем его (Enabled = False). Последним действием при добавлении элемента в очередь - включаем. При обработке события OnTimer - вытаскивание элемента, если очередь не пуста или отключение таймера, если она пуста.ZigZagkms писал(а):Максим, здравствуйте.
один выход из проблемы - использовать импортируемую функцию только в главном потоке CommFortProcess (как Вы и сказали что ее можно использовать только в главном потоке), я подумал создать очередь запросов к функции которая наполняется вторым потоком, НО главный вопрос как обслуживать (выталкивать и исполнять) эту очередь в первом потоке?
Формы у меня в проекте нету. Насколько мне известно таймер он посылает сообщение окну WM_TIMER и тогда уже выполняется функция, была бы форма было бы проще посылать сообщения самому со своим идентификатором и выполнять, хотя в этом я тоже могу ошибаться, не долго я с С++ работаю, как раз с тех самых пор когда разработчики отказались от UDP=) Добавлять форму ради таймера не охота, слишком большие затраты.KGB писал(а):Предложу один вариант, хотя он может быть и неверным. Заполнение и вытаскивание элементов из очереди - критические секции (это и так понятно). Можно воспользоваться таймером, созданным в основном потоке (интервал - 1мс). При инициализации отключаем его (Enabled = False). Последним действием при добавлении элемента в очередь - включаем. При обработке события OnTimer - вытаскивание элемента, если очередь не пуста или отключение таймера, если она пуста.
Время ожидания добавления элемента в очередь мне кажется не особо критичным в этом случае.
Если неправ, просьба не бить, только учусь
Создавать таймер можно и в процессе выполнения, в том числе без родительской формы. От сообщений, конечно, никуда не деться, но в этом случае таймер создаёт собственное окно. И затраты будут только на него (вот тут уже я могу ошибаться).ZigZagkms писал(а): Формы у меня в проекте нету. Насколько мне известно таймер он посылает сообщение окну WM_TIMER и тогда уже выполняется функция, была бы форма было бы проще посылать сообщения самому со своим идентификатором и выполнять, хотя в этом я тоже могу ошибаться, не долго я с С++ работаю, как раз с тех самых пор когда разработчики отказались от UDP=) Добавлять форму ради таймера не охота, слишком большие затраты.
Блин. Ёлки-палки, лес дремучий.@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);//тут имя твоего пользователя
Вот сама функция:[Error] main.pas(339): Incompatible types: 'String' and 'PAnsiChar'
[Error] main.pas(340): Incompatible types: 'String' and 'PAnsiChar'
С дельфи не проконсультирую, ошибка точно в первом вызове. Тут во втором параметре должен быть 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;
}
Вопрос ко всем, в том числе и к самому Максиму:Maxim Mirgorodsky писал(а): Изменения по системе плагинов в сервере 5.03:
...
- Исправлена ошибка при получении данных от программы с ID=1080;
...
Код: Выделить всё
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);