大家好,在罗云彬的《windows环境下32位汇编语言程序设计》第十六章中有一个阻塞模式下TCP聊天室的小程序。作者最后还提出了四个小问题:1.在聊天信息中加入用户发言的时间;2.限制用户灌水;3.限制用户重复登录;4.实现悄悄话的功能。我经过一段时间的调试,把这几个小功能都实现了。现在把我的思路写下,供大家参考。
在聊天信息中加入用户发言的时间:
1.在Message.inc中,改变MSG_DOWN结构体。
MSG_DOWN    struct
  szTime      db  20 dup (?)  ;canmeng萌1
  szSender    db  12 dup (?)  ;消息发送者
  dwLength    dd  ?    ;后面内容字段的长度
  szContent    db  256 dup (?)  ;内容,不等长,长度由dwLength指定
MSG_DOWN    ends
发言时间我定义为如下格式:2009-12-17 12:13:56,占19个字节,再加上用于结尾的0字符,正好占20个字节。所以定义szTime为20个字节。
2.在_MsgQueue.asm中,
①改变消息结构体
MSG_QUEUE_ITEM  struct      ;队列中单条消息的格式定义
  dwMessageId  dd  ?    ;消息编号
  szSender  db  12 dup (?)  ;发送者
  szContent  db  256 dup (?)  ;聊天内容
  szTime  db  20  dup (?)  ;canmeng萌1
MSG_QUEUE_ITEM  ends
②在.data?段中定义一个SYSTEMTIME类型的变量_szTime
_szTime  SYSTEMTIME  <?>    ;canmeng萌1
定义六个双字类型的全局变量sztemp1,sztemp2,sztemp3,sztemp4,sztemp5,sztemp6,分别用来存放所返回的时间的年、月、日、时、分、秒。
sztemp1  dd  ?    ;canmeng萌1
sztemp2  dd  ?    ;canmeng萌1
sztemp3  dd  ?    ;canmeng萌1
sztemp4  dd  ?    ;canmeng萌1
sztemp5  dd  ?    ;canmeng萌1
sztemp6  dd  ?    ;canmeng萌1
再定义一个128个字节的缓冲区变量szTimeBuffer,用来存放返回的时间。
szTimeBuffer  db  128 dup (?)      ;canmeng萌1
③在.const段中顶一个变量szTimeStyle,用它来规定时间的格式。
    .const                ;canmeng萌1
szTimeStyle  db  '%d-%d-%d %d:%d:%d',0    ;canmeng萌1
④修改_InsertMsgQueue函数
准确的说,放到消息队列中去的不是用户发言时的时间,而是用户把聊天语句发给服务器后,服务器把这条聊天语句插入到消息队列时的时间。
调用GetLocalTime函数,经过处理后得到所需要的时间。
invoke  GetLocalTime,addr _szTime      ;canmeng萌1,获得当前系统时间
    movzx  eax,_szTime.wYear        ;canmeng萌1
    mov  sztemp1,eax          ;canmeng萌1
    movzx  eax,_szTime.wMonth        ;canmeng萌1
    mov  sztemp2,eax          ;canmeng萌1
    movzx  eax,_szTime.wDay        ;canmeng萌1
    mov  sztemp3,eax          ;canmeng萌1
    movzx  eax,_szTime.wHour        ;canmeng萌1
    mov  sztemp4,eax          ;canmeng萌1
    movzx  eax,_szTime.wMinute        ;canmeng萌1
    mov  sztemp5,eax          ;canmeng萌1
    movzx  eax,_szTime.wSecond        ;canmeng萌1
    mov  sztemp6,eax          ;canmeng萌1
    invoke  wsprintf,addr szTimeBuffer,addr szTimeStyle,sztemp1,sztemp2,\
        sztemp3,sztemp4,sztemp5,sztemp6    ;canmeng萌1
    invoke  lstrcpy,addr [esi].szTime,addr szTimeBuffer  ;canmeng萌1,这样消息中就包含聊天的时间了  
⑤修改_GetMsgFromQueue函数
_GetMsgFromQueue的参数加上一个_lpszTime参数,它代表一个缓冲区指针,这个缓冲区用来存放消息中的szTime字段中的时间。
_GetMsgFromQueue  proc  _dwMessageId,_lpszSender,_lpszContent,_lpszTime    ;canmeng萌1
            
            
      invoke  lstrcpy,_lpszTime,addr [esi].szTime      ;canmeng萌1
3.在Server.asm中,当服务器端的某一个线程收到对应的客户端发来的聊天语句时(MSG_UP数据包),就会调用_InsertMsgQueue函数添加上当前时间把本条消息放到消息队列中,然后再调用_GetMsgFromQueue函数把消息取出,组成一个MSG_DOWN结构体,发送出去。服务器是通过_SendMsgFromQueue间接调用_GetMsgFromQueue的。由于_GetMsgFromQueue已经多了一个输入参数,所以也要修改_SendMsgFromQueue函数。
在_SendMsgFromQueue中,
Invoke _GetMsgFromQueue,ecx,addr [esi].MsgDown.szSender,addr [esi].MsgDown.szContent,\
          addr [esi].MsgDown.szTime      ;canmeng萌1
4.在Client1.asm中,当客户端收到服务器端发来的MSG_DOWN数据包时,只需要把其中的szTime字段的值提取出来并显示就行了。
把收到数据包后的处理语句修改为如下格式:
;********************************************************************
; 循环接收消息
;********************************************************************
.if  @stMsg.MsgHead.dwCmdId == CMD_MSG_DOWN
  invoke  lstrcpy,addr @szBuffer,addr @stMsg.MsgDown.szContent  ;canmeng萌1,先显示内容
  invoke  SendDlgItemMessage,hWinMain,IDC_INFO,LB_INSERTSTRING,0,addr @szBuffer
          
  invoke  lstrcpy,addr @szBuffer,addr @stMsg.MsgDown.szSender
  invoke  lstrcat,addr @szBuffer,addr szSpar
          
  invoke  lstrcat,addr @szBuffer,addr @stMsg.MsgDown.szTime    ;canmeng萌1
  invoke  SendDlgItemMessage,hWinMain,IDC_INFO,LB_INSERTSTRING,0,addr @szBuffer;canmeng萌1
.endif
这样,第一步完成了。可以正常显示时间了。呵呵
附件中是经过修改的源代码,在修改的地方我都做了标记。

上传的附件 1显示发言时间.rar