首页
论坛
课程
招聘
[旧帖] [原创]罗云彬《32位汇编语言》16章中对TCP聊天室程序的扩展3 0.00雪花
2009-9-19 21:52 903

[旧帖] [原创]罗云彬《32位汇编语言》16章中对TCP聊天室程序的扩展3 0.00雪花

2009-9-19 21:52
903
第三步就是实现限制用户重复登录的功能。
1.        在Server.asm中,定义了一个48个字节的全局变量szusernames,每个用户占12个字节,所以最多只能同时登录4个用户。当收到客户端发过来的“登录数据包”时,首先判断此时的dwThreadCounter的值,如果为1则说明这是第一个登录的用户,不用和谁能行比较了,把这个登录的用户名放到szusernames的前12个字节中,并发回一个“登录成功”数据包(CMD_LOGIN_RESP数据包,dbResult字段为0);如果dwThreadCounter>=5,说明这是第五个登录的用户,而我这个服务器最多只支持4个用户登录,返回一个“登录用户太多”数据包(dbResult字段为2,这是我自定义的);如果dwThreadCounter>1并且<5,说明已经有用户登录过了,于是就要判断这个刚登录的用户的用户名有没有被使用过。如果没有被使用过,就把这个登录的用户的用户名放进szusername的某个12个字节中,发回“登录成功”数据包,如果被使用过了,就直接发回一个“登录失败(deResult字段为1)”数据包了。

.data
szusernames        db        48 dup (?)                                                ;canmeng萌3

当服务器收到用户登录数据包时,首先进行判断:
;********************************************************************
; 用户名和密码检测,为了简化程序,现在可以使用任意用户名和密码
;********************************************************************
invoke        _RecvPacket,_hSocket,esi,sizeof @szBuffer
                or        eax,eax
                jnz        _Ret
                .if        [esi].MsgHead.dwCmdId != CMD_LOGIN
                        jmp        _Ret
                .else
                        invoke        lstrcpy,addr [edi].szUserName,addr [esi].Login.szUserName
;如果登录的只有我自己一个用户,那当然不用和谁进行比较啦
                        .if        dwThreadCounter<=1                                                        ;canmeng萌3
                                jmp _register                                                                        ;canmeng萌3
                        .elseif        dwThreadCounter>=5                                                ;canmeng萌3
                                jmp _usertoomuch                                                                ;canmeng萌3
                        .else                                                                                                ;canmeng萌3
                                mov ecx,dwThreadCounter                                                ;canmeng萌3
                                sub ecx,1                                                                                ;canmeng萌3
                                .repeat                                                                                        ;canmeng萌3                                                        nop                                                                                        ;canmeng萌3
                                        sub ecx,1                                                                        ;canmeng萌3
                                        mov eax,12                                                                        ;canmeng萌3
                                        mul ecx                                                                                ;canmeng萌3
                                        mov edx,offset szusernames                                        ;canmeng萌3       
                                        add edx,eax                                                                        ;canmeng萌3
                                       
                                        push ecx                                                                        ;canmeng萌3
                                        push edx                                                                        ;canmeng萌3       
                                        invoke        lstrcmp,edx,addr [esi].Login.szUserName        ;canmeng萌3
                                        .if eax==0                                                                                ;canmeng萌3
                                                pop edx                                                                                        ;canmeng萌3
                                                pop ecx                                                                                        ;canmeng萌3
                                                jmp _shibai                                                                                ;canmeng萌3
                                        .endif                                                                                                ;canmeng萌3
                                        pop edx                                                                                                ;canmeng萌3
                                        pop ecx                                                                                                ;canmeng萌3
                                .until        cx==0                                                                                        ;canmeng萌3
                        .endif                                                                                                                ;canmeng萌3
;********************************************************************
;把这个登录的用户名放到用户名表中                       
_register:                mov ecx,dwThreadCounter                                                        ;canmeng萌3
                        sub ecx,1                                                                                                ;canmeng萌3
                        mov eax,12                                                                                                ;canmeng萌3
                        mul ecx                                                                                                        ;canmeng萌3
                        mov edx,offset szusernames                                                                ;canmeng萌3
                        add edx,eax                                                                                                ;canmeng萌3
                        invoke        lstrcpy,edx,addr [esi].Login.szUserName                        ;canmeng萌3       
                       
                        mov        [esi].LoginResp.dbResult,0                                       
                        jmp        fanhui                                                                                                ;canmeng萌3
_shibai:                mov        [esi].LoginResp.dbResult,1                                                ;canmeng萌3
                        jmp        fanhui                                                                                                ;canmeng萌3       
_usertoomuch:                mov        [esi].LoginResp.dbResult,2                                ;canmeng萌3
                .endif
fanhui:                                                                                                                                ;canmeng萌3
                mov        [esi].MsgHead.dwCmdId,CMD_LOGIN_RESP
                mov        [esi].MsgHead.dwLength,sizeof MSG_HEAD+sizeof MSG_LOGIN_RESP
在这个程序中的push  ecx,push  edx和pop  ecx,pop  edx实在是无奈之举,这是因为lstrcmp函数会影响他们的值。我也不知道这是为什么。

当有客户退出聊天室的时候,要在szusernames中把该用户名清除,并把后面的用户名统一向前移动12个字节。
;********************************************************************
; 广播:xxx 退出了聊天室
;********************************************************************
                invoke        lstrcpy,esi,addr [edi].szUserName
                invoke        lstrcat,esi,addr szUserLogout
                invoke        _InsertMsgQueue,addr szSysInfo,addr @szBuffer
;*************************************************************        ;canmeng萌3
;清除这个线程对应的用户名,并把后面的所有用户名统一向前面移动12个字节
;*************************************************************        ;canmeng萌3
invoke        WaitForSingleObject,hEvent,INFINITE                        ;canmeng萌3,等待事件对象置位
                mov edx,offset szusernames                                        ;canmeng萌3
                mov ecx,1                                                                        ;canmeng萌3
                .while TRUE                                                                        ;canmeng萌3
                        push edx                                                        ;canmeng萌3
                        push ecx                                                        ;canmeng萌        3               
                        invoke lstrcmp,edx,addr [edi].szUserName                        ;canmeng萌3
                        pop ecx                                                                ;canmeng萌3
                        pop edx                                                                ;canmeng萌3       
                        .break .if eax==0                                                ;canmeng萌3
                        add edx,12                                                        ;canmeng萌3
                        add ecx,1                                                        ;canmeng萌3
                .endw                                                                        ;canmeng萌3

                mov edi,edx                                                                ;canmeng萌3
                mov esi,edx                                                                ;canmeng萌3
                add esi,12                                                                ;canmeng萌3
                mov eax,dwThreadCounter                                ;canmeng萌3
                sub eax,ecx                                                                ;canmeng萌3       
                mov ecx,eax                                                                ;canmeng萌3
                mov eax,12                                                                ;canmeng萌3
                mul ecx                                                                        ;canmeng萌3
                mov ecx,eax                                                                ;canmeng萌3
                cld                                                                                ;canmeng萌3
                rep movsb                                                                ;canmeng萌3
;********************************************************************
; 关闭 socket
;********************************************************************
_Ret:
                invoke        closesocket,_hSocket
                dec        dwThreadCounter
                invoke        SetEvent,hEvent                                                ;canmeng萌3,置位事件对象

在编程中由于涉及到了多线程的同步问题,所以我创建了一个事件对象。在.data段中定义了一个全局变量hEvent,用于存放事件对象的句柄。
hEvent        dd        ?                ;canmeng萌3

主窗口程序中当初始化对话框时创建一个事件对象
.if        eax ==        WM_INITDIALOG
……
invoke         CreateEvent,NULL,FALSE,TRUE,NULL        ;canmeng萌3,创建一个事件对象
                        mov        hEvent,eax                                                        ;canmeng萌3

关闭对话框时就关闭事件对象句柄
.elseif        eax ==        WM_CLOSE
……
invoke        CloseHandle,hEvent                                ;canmeng萌3,关闭事件对象的句柄

在程序中总共有两处用到了WaitForSingleObject,SetEvent这一对。第一次是_ServiceThread的开始处,第二次是广播“***退出了聊天室”之后。
2.在Client1.asm中

在.const段中定义一个全局变量sztoomuch,当用户作为第五个用户时就跳出这个提示。
.const
sztoomuch        db        '无法登录到服务器,最多只能登录4个用户,您是第五个!',0       

当客户端收到服务器发来的“登录回应”数据包时,判断里面的dbResult字段。
invoke_RecvPacket,hSocket,addr @stMsg,sizeof @stMsg
        or        eax,eax
        jnz        @F
        cmp        @stMsg.MsgHead.dwCmdId,CMD_LOGIN_RESP
        jnz        @F
        .if        @stMsg.LoginResp.dbResult==1                                        ;canmeng萌3
                @@:
                invoke        MessageBox,hWinMain,addr szErrLogin,NULL,MB_OK or MB_ICONSTOP
                jmp        _Ret
        .elseif        @stMsg.LoginResp.dbResult==2                ;canmeng萌3,如果值为2代表登录人数太多
                invoke        MessageBox,hWinMain,addr sztoomuch,NULL,MB_OK                ;canmeng萌3
                jmp        _Ret
        .endif
这样,第三个问题限制用户重复登录也解决了。
附件是源代码。

[2022冬季班]《安卓高级研修班(网课)》月薪三万班招生中~

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回