Помогите с алгоритмом антифлуда в чат-ботах

Тема в разделе "WASM.ASSEMBLER", создана пользователем Flasher, 8 авг 2006.

  1. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    Например сделать так, если промежуток между сообщениями меньще 3 сек. - kick.
    Я смог реализовать токо один способ, но он с проблемами.

    Если кто-то пишет в чате, бот проверяет, если нету, то заводит структуру на этот ник и присоединяет к массиву структур, вот так:
    Код (Text):
    1. ACCAUNTINFO struct
    2.      NickLen dd ?
    3.      NickBuf dd ?
    4.      MinBuf dd ?
    5.      SecBuf dd ?
    6.      NextLink dd ?
    7. ACCAUNTINFO ends
    8.  
    9. NumArray dd 256 dup(?)
    10. szTime db "mmss",0
    11.  
    12. AddNickStruct proc scr:dword
    13.      local buffer[128]:byte
    14.        
    15.        invoke lstrlen,scr
    16.        push eax
    17.        lea esi,buffer
    18.        mov edi,scr
    19.        mov ecx,eax
    20.     @@:
    21.        mov al,byte ptr [edi]
    22.        mov byte ptr [esi],al
    23.        inc esi
    24.        inc edi
    25.        dec ecx
    26.        jnz @B
    27.        mov byte ptr [esi],0
    28.        
    29.        invoke GlobalAlloc,0h or 40h,sizeof ACCAUNTINFO
    30.        mov esi,eax
    31.        assume esi:ptr ACCAUNTINFO
    32.        pop eax
    33.        mov [esi].NickLen,eax
    34.        mov [esi].MinBuf,0
    35.        mov [esi].SecBuf,0
    36.  
    37.        invoke GlobalAlloc,0h or 40h,eax
    38.        mov [esi].NickBuf,eax
    39.        invoke lstrcpy,[esi].NickBuf,addr buffer
    40.      
    41.        mov eax,offset NumArray
    42.        movzx edx,byte ptr [buffer]
    43.        shl edx,2
    44.        add eax,edx
    45.         .if dword ptr [eax]==0
    46.            mov dword ptr [eax],esi
    47.         .else
    48.            push dword ptr [eax]
    49.            pop [esi].NextLink
    50.            mov dword ptr [eax],esi
    51.         .endif
    52.        assume esi:nothing
    53.        ret
    54. AddNickStruct endp
    55.  
    56. ; А сама процедура сравнения выглядит так
    57. AntiFlood proc scr:dword
    58.      local hYes:dword
    59.      local AddNick[128]:byte
    60.      local TimeBuf[256]:byte
    61.      local _min[4]:byte
    62.      local _sec[4]:byte
    63.  
    64.        invoke lstrcpy,addr AddNick,scr
    65.        mov hYes,0
    66.        lea esi,AddNick
    67.        invoke lstrlen,esi
    68.        mov edx,eax
    69.        movzx ebx,byte ptr [esi]
    70.        shl ebx,2
    71.        add ebx,offset NumArray
    72.         .if dword ptr [ebx]!=0
    73.            mov ebx,dword ptr [ebx]
    74.            assume ebx:ptr ACCAUNTINFO
    75.             .while ebx!=0
    76.                .if edx==[ebx].NickLen
    77.                   push edx
    78.                   push ebx
    79.                   invoke lstrcmpi,[ebx].NickBuf,esi
    80.                    .if eax==0
    81.                       mov hYes,1
    82.                       invoke GetTimeFormat,0,TIME_FORCE24HOURFORMAT,0,offset szTime,addr TimeBuf,256
    83.                       mov al,byte ptr [TimeBuf+0]
    84.                       mov byte ptr [_min+0],al
    85.                       mov al,byte ptr [TimeBuf+1]
    86.                       mov byte ptr [_min+1],al
    87.                       invoke atodw,addr _min ; получаем минуты
    88.                       pop ebx
    89.                       pop edx
    90.                        .if eax == [ebx].MinBuf ; если равно получаем секунды
    91.                           mov al,byte ptr [TimeBuf+2]
    92.                           mov byte ptr [_sec+0],al
    93.                           mov al,byte ptr [TimeBuf+3]
    94.                           mov byte ptr [_sec+1],al
    95.                           invoke atodw,addr _sec ; получаем секунды
    96.                           mov edx,eax
    97.                           sub edx,[ebx].SecBuf ; отнимаем от нынешнего прошедшую
    98.                            .if edx < 3 ; если разница меньще 3 сек - кикаем
    99.                               push ebx
    100.                ;kick
    101.                               pop ebx
    102.                               mov [ebx].NickLen,0
    103.                               mov [ebx].MinBuf,0
    104.                               mov [ebx].SecBuf,0
    105.                               invoke GlobalFree,[ebx].NickBuf
    106.                            .else
    107.                               mov [ebx].SecBuf,eax ; присвоиваем
    108.                            .endif
    109.                        .else
    110.                           mov [ebx].MinBuf,eax ; если не равно, присвоиваем
    111.                        .endif
    112.             .break
    113.                    .endif
    114.                   pop ebx
    115.                   pop edx
    116.                .endif
    117.               mov ebx,[ebx].NextLink
    118.             .endw
    119.            assume ebx:nothing
    120.         .endif
    121.        .if hYes != 1 ; если нет такого чуловека, добавляем
    122.           invoke AddNickStruct,addr AddNick
    123.        .endif
    124.        ret
    125. AntiFlood endp
    Хотю заметит что подпрограмма составления структурных массивов и их сравнения принадлежат дяденьке Iczelion'у, я просто под себя подкоректировал..

    Есть проблемка, если много рас вызвать GlobalAlloc, прога выдаёт ошибку и падает..
    Помогите плиз либо улучшить этот вариант, либо слушаю ваши алгоритмы по решению данной задачи...
    Спасибо!
     
  2. Bohdan200

    Bohdan200 New Member

    Публикаций:
    0
    Регистрация:
    13 сен 2005
    Сообщения:
    134
    Адрес:
    Lviv
    Так будет гораздо проще. И быстрее.

    Код (Text):
    1. AddNickStruct proc scr:dword
    2.     invoke  HeapAlloc, hHeap, 0, sizeof ACCAUNTINFO
    3.     mov esi, eax
    4.     assume  esi:ptr ACCAUNTINFO
    5.     invoke  lstrlen, scr
    6.     mov [esi].NickLen,eax
    7.     inc eax
    8.     invoke  HeapAlloc, hHeap, 0, eax
    9.     mov [esi].NickBuf, eax
    10.     invoke  lstrspy, eax, scr
    11.     mov [esi].MinBuf,0
    12.     mov [esi].SecBuf,0
    13.     ; Дальше что-то непонятное делаем с первой буквой ника...
    структура ACCAUNTINFO не совсем понятна
    что такое MinBuf, SecBuf, NextLink?

    Я так понял, что у тебя односвязный список и указатель на стедующую структуру лежит в NextLink? А где лежит указатель на первую структуру?

    mov eax,offset NumArray
    movzx edx,byte ptr [buffer] - тут код первая буква ника
    shl edx,2
    add eax,edx
    .if dword ptr [eax]==0 - если NumArray[первая буква ника] == 0
    mov dword ptr [eax],esi - вносим туда указатель на созданную структуру
    .else
    push dword ptr [eax] - иначе в NextLink структуры вносим NumArray[ник]
    pop [esi].NextLink
    mov dword ptr [eax],esi - а в NumArray[ник] - указатель на созданную структуру
    .endif

    Ничерта тут не понял...
     
  3. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    http://wasm.ru/article.php?article=1001035
    :)
    замена GlobalAlloc на HeapAlloc не помогло.
     
  4. Bohdan200

    Bohdan200 New Member

    Публикаций:
    0
    Регистрация:
    13 сен 2005
    Сообщения:
    134
    Адрес:
    Lviv
    Тут мало общего с твоей задачей, и адаптировать готовое решение к твоей задаче - слишком сложный и неоправданый труд. Ессно это IMHO, но на твоем месте я бы сделал приблизительно так:

    Код (Text):
    1. .data
    2. ACCOUNTINFO struct
    3.     szNick db 64 dup (?)    ; никогда не видел ников, длиннее 63 символов
    4.     LastMessageTime dd ?    ; а тут - время отправки последнего сообщения
    5.     next dd ?   ; указатель на структуру следующего пользователя
    6. ACCOUNTINFO ends
    7.  
    8. hHeap dd 0
    9. pFirstAccount dd 0
    Код (Text):
    1. ; Процедура сравнения ников
    2. CheckName proc uses ecx esi edi pszNick:PCHAR, pAccount:ptr ACCOUNTINFO
    3.  
    4.     xor ecx, ecx
    5.     mov esi, pszNick
    6.     mov edi, pAccount
    7.    
    8.     .while (ecx<32 && BYTE ptr [esi+ecx]>0)
    9.       mov al, BYTE ptr [esi+ecx]
    10.       .if (al!=BYTE ptr [edi+ecx])
    11.         .break
    12.       .endif
    13.       inc ecx
    14.     .endw
    15.    
    16.     xor eax, eax
    17.     .if(ecx==32)
    18.       inc eax
    19.     .endif
    20.     ret
    21. CheckName endp
    Код (Text):
    1. ; Вызываем при каждом сообщении
    2. CheckUser proc pszNick:PCHAR
    3. local TimeStamp:DWORD
    4.  
    5.     invoke GetTickCount
    6.     mov TimeStamp, eax
    7.    
    8.     mov esi, pFirstAccount
    9.     assume esi:ptr ACCOUNTINFO
    10.     assume edi:ptr ACCOUNTINFO
    11.    
    12.     xor edi, edi
    13.     .while(esi!=NULL)
    14.        invoke CheckName, pszNick, esi
    15.        .if(eax!=0)
    16.           .break
    17.        .endif
    18.        mov edi, esi
    19.        mov esi, [esi].next
    20.     .endw
    21.    
    22.     .if(esi==NULL)
    23.        invoke HeapAlloc, hHeap, 0, sizeof ACCOUNTINFO
    24.        mov esi, eax
    25.        .if(edi!=NULL)
    26.           mov [edi].next, esi
    27.        .else
    28.           mov pFirstAccount, esi
    29.        .endif
    30.        mov eax, TimeStamp
    31.        mov [esi].LastMessageTime, eax
    32.        mov [esi].next, 0
    33.        invoke lstrcpyn, [esi].szNick, pszNick, 64
    34.     .else
    35.        mov eax, TimeStamp
    36.        sub eax, [esi].LastMessageTime
    37.        .if(eax>3000)
    38.           invoke KickUser, pszNick
    39.           ; еще тут можно освободить память под  структуру кикнутого юзверя, если хочеш
    40.           ; ну и пересвязять односвязный список, ессно
    41.        .endif
    42.        mov eax, TimeStamp
    43.        mov [esi].LastMessageTime, eax
    44.     .endif
    45.    
    46.     assume edi:nothing
    47.     assume esi:nothing
    48.     ret
    49. CheckUser endp
    Ошибок тут наверно немеряно, писал на скорую руку и не проверил. Думаю розберешся.
     
  5. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    Увы, не смог :)
    Рас стоко строк писал ради того чтоб помочь хотяб разок пропустил через компилятор..
    А то вроди и с сравнением проблемы, и в области lstrcpyn.
    Чувствую и HeapAlloc будет выдавать ошибки при многократном вызове.

    По большёму счёту ты сделал тоже самое...
    Iczelion'овский вариант быстрее.
    Благодаря твоему примеру теперь в том варианте память под ник не выделяю, и это гуд, осталось как-нить справиться с памятью под структуру, есть идеи ? :)
     
  6. Bohdan200

    Bohdan200 New Member

    Публикаций:
    0
    Регистрация:
    13 сен 2005
    Сообщения:
    134
    Адрес:
    Lviv
    В сравнении ников все 32 надо поменять на 64 и конечный if поправить.
    Структура ACCOUNTINFO занимает 72 байта. На каждый мегабайт оперативы влазит 14563 юзверя. Не пойму что за проблемы с выделением памяти.
     
  7. Bohdan200

    Bohdan200 New Member

    Публикаций:
    0
    Регистрация:
    13 сен 2005
    Сообщения:
    134
    Адрес:
    Lviv
    Код (Text):
    1. CheckName proc uses ecx esi edi pszNick:PCHAR, pAccount:ptr ACCOUNTINFO
    2.  
    3.     xor ecx, ecx
    4.     mov esi, pszNick
    5.     mov edi, pAccount
    6.    
    7.     .while (ecx<32 && BYTE ptr [esi+ecx]>0)
    8.       mov al, BYTE ptr [esi+ecx]
    9.       .if (al!=BYTE ptr [edi+ecx])
    10.         jmp NotEqual
    11.       .endif
    12.       inc ecx
    13.     .endw
    14.     xor eax, eax
    15.     inc eax
    16.     ret
    17.  
    18. NotEqual:
    19.     xor eax, eax
    20.     ret
    21. CheckName endp
    ну если не нравится 64, то делай
    Код (Text):
    1. invoke lstrlen, pszNick
    2. invoke lstrcpyn, [esi].szNick, pszNick, eax
    Это все лень... :)
     
  8. Chingachguk

    Chingachguk New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2002
    Сообщения:
    340
    Имхо, проще всего пройти в отладчике код и посмотреть, сколько там памяти выделилось при первом, втором добавлении...
     
  9. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    аха, лень.., спасибо за помощь. ;)
    кстати, и знак надо поменять .if(eax>3000), а то потестил, все кто что-то говорил - кикало :)) долго размышлял над этим :)