我最近在编写一个局域网聊天的软件,现在遇到一个问题:在客户端同时下线时,服务器只会处理一个客户端下线.麻烦大家帮我看一下问题出在哪?下面是部分代码:
if msg.command='offOnline' then
  begin
   athread.Synchronize(offonline);
    for i:=0 to high(online) do  //删除下线用户的联机节点
     begin
       if online[i].userName=msg.userName then
       begin
          online[i]:=online[high(online)];
          setlength(online,high(online));
          break;
       end;
     end;
      rec.command:='deleOnline';
      rec.userName:=msg.userName;
     for i:=0 to high(online) do   //发送下线用户的用户名
       begin
        online[i].AThread.Connection.WriteBuffer(rec,sizeof(rec));
       end;  end;procedure Tmain.offonline;
var
 i:integer;
begin
    for i:=0 to listview1.Items.Count-1 do
     begin
        if listview1.Items.Item[i].Caption=msg.userName then
        begin
           listview1.Items.Item[i].Delete;
           break;
        end;
     end;
     memo1.Lines.Add('用户 '+msg.userName+' 下线了');
end;

解决方案 »

  1.   

    一眼看过去你的msg变量有问题,多个用户同时下线msg.userName=??
      

  2.   

    msg是客户端传给服务器的消息包,我是设定客户端关闭是发出含有用户名和下线命令标志的msg包,这样编写不行吗?但是一个个下线是正常的同时下的话就只能下一个
    说明一下:listview是用来显示上线客户端信息的,rec是服务器发给客户端的消息包,online是array of RrectiveData RrectiveData=record 
        command:string[10];
        userName:string[20];
        fromWho:string[20];
        toWho:string[20];
        side:integer;
        color:Tcolor;
        text:string[100];
        AThread:TIdPeerThread;
    RmessageData=record
        command:string[10];
        userName:string[20];
        password:string[20];
        IP:string[15];
        port:string[10];
        fromWho:string[20];
        toWho:string[20];
        side:integer;
        color:Tcolor;
        text:string[100];
      

  3.   

    从代码来看,你没有单独操作每个用户的msg,每个客户端在服务器都会对应一个线程,大家都去操作同一个msg并发就有问题了。这里有一个多线程操作的概念,全局变量,如online,要互斥操作。 if online[i].userName=msg.userName then
           begin
              online[i]:=online[high(online)];
              setlength(online,high(online));
              break;
           end;仔细一看这段代码蹊跷,下线的又不一定是最后一个用户,无辜的给你挤掉了...
      

  4.   

    这个你理解错了,这段代码意思是如果在 online[i]中找到符合的节点,就将online中最后一个用户写入到当前的的online[i]中,同时删除最后一个节点.不过听你这么一说我大概知道问题在哪里了:我将msg设为全局变量了,导致只有接收到一个msg包就并发了.
    不过我还有个问题:我如果将程序改为TThreadlist的listlock锁住每个线程,线程中是否就可以不用Synchronize()?换句话说线程listlock后是否就一定是安全的?
      

  5.   

    确实看错... @_@对Synchronize的调用主要原因不是因为线程安全,而是因为VCL的界面操作都应该都交给主线程进行。要想不用Synchronize也可以,建议给用户一个id,然后用SendMessage/PostMessage来告知主线程用户删除操作。TThreadlist的locklist只是对线程列表本身互斥访问,和每个线程自己的操作没什么关系。对online的全局变量操作需要自己使用criticalSection来同步。
      

  6.   

    每个TCPserver端被连接后,自动会有一个相应线程,我也正在在试着用IDTCP控件做一个局域网的聊天工具,有兴趣可以聊啊,[email protected]
      

  7.   

    这么一说我就明白了,非常非常感谢qlwuu(沉睡火山)给我得帮助,另外,,我很乐意与各位交流,虽然我很菜......