INDY自代的例子看了一下,以前用过TServerSocket做过这方面的东西!
  TCommBlock = record   // the Communication Block used in both parts (Server+Client)
     Command: TCommand;
     MyUserName,                 // the sender of the message
     Msg,                        // the message itself
     ReceiverName: string[100];  // name of receiver
   end;
这是他里面的协议的定义,我这里需要的类似的MSN那种 ,先登录,然后是简单的信息通讯,客户大概100左右!我觉得INDY应该能承受的住!这个协议如何能定议的比较灵活,为以后扩展打下基础!希望大家讨论一下!或是有这方面的经验,交流一下!

解决方案 »

  1.   

    呵呵..楼主干嘛不直接找一下MSN的协议格式了?
      

  2.   

    其实要看你要实现多少东西
    最好好是udp-p2p,你用tcp想转发吗? 不好,特别是语音,视频聊天,
    我自己写的一般是定义大包(包头+包身),接收读包头,确定内容什么再读,
    这个是简单的思路
      

  3.   

    洋人有一个开放的及时通讯协议XMPP,gtalk用的就是这个,Jabber是服务器部分实现,而且开放源代码。
      

  4.   

    谢谢楼上二位的回答
    其实暂时没那么复杂,暂时只有文字的互相传递!但是要为以后扩展做好准备,所以各方面要考虑的比较多。
    TO halfdream(哈欠):嗯,我想应该先看一下MSN的协议,必究他的是典型的TCP转发的模式!
    TO constantine(飘遥的安吉儿) :因为用户连接数不太多,所以直接用INDY的TCP我觉得足够,如果要考虑大用户还有从完成端口方面考虑!
      

  5.   

    自定义数据包:包头+包身。
    比如包头用byte类型,并定义成常量,代表不同的数据包。
    数据包就按需求定义了,比如有登陆包、聊天信息包等。
    接收时先接包头,分析包头后就可以接收不同的数据包了。以后扩展,增加新的数据包和数据头就可以了。如果是视频音频等数据,需要用数据流接收,同样使用这种包头和数据流分开的结构。
      

  6.   

    如果用INDY的例子:
    TCommBlock = record   // the Communication Block used in both parts (Server+Client)
         Command: TCommand;
         MyUserName,                 // the sender of the message
         Msg,                        // the message itself
         ReceiverName: string[100];  // name of receiver
       end;
    这可能就是一个聊天包,包头可能需要定义一个BYTE的值,1可能为聊天包,接收时如何做呢,用MEMORYSTREAM接收,还是先接收包头,然后跟着接收包内容!谢谢
      

  7.   

    我的做法是这样的:
    TCommBlock = record   // the Communication Block used in both parts (Server+Client)
         Command: TCommand;
    end;TBlock = record   // the Communication Block used in both parts (Server+Client)
         MyUserName,                 // the sender of the message
         Msg,                        // the message itself
         ReceiverName: string[100];  // name of receiver
       end;
    end;
    发送用WriteBuffer,分两次发;
    接收用ReadBuffer(CommBlock,sizeof(TCommBlock));先接收包头,接着就知道包体是哪个,大小是多少了,还是用ReadBuffer接收
      

  8.   

    谢谢cjf1009(农民程序员) 的回复!
    但会不会出现不同步的情况?接到包头,包内容发送太快而丢包或其他情况呢??!!!
      

  9.   

    还是关于INDY的DEMO的问题,
    procedure TServerFrmMain.Button1Click(Sender: TObject);
    var
      i: integer;
      ActClient: PClient;
      RecThread: TIdPeerThread;
      NewCommBlock: TCommBlock;
    begin
      try
        for i := 0 to Clients.LockList.Count - 1 do
          begin
            NewcommBlock.Command := cMessage;
            NewcommBlock.MyUserName := 'system';
            NewcommBlock.Msg := 'system test';
            NewcommBlock.ReceiverName := '';        
            ActClient := Clients.LockList.Items[i];
            RecThread := ActClient.Thread;
            RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);
          end;
      finally
        Clients.UnlockList;
      end;
    end;
    我做了一个群发的测试,群发没问题,但当群发后,SERVER接收不到客户端的任何消息!!怀疑是TThreadList的问题,但是procedure TServerFrmMain.ServerExecute(AThread: TIdPeerThread);里发任何东西没有这样的问题,是线程安全,同步,还是什么问题??希望大家帮忙 !!
      

  10.   

    但会不会出现不同步的情况?接到包头,包内容发送太快而丢包或其他情况呢??!!!
    ——————————————————————————
    不会。tcp/ip协议是传输可靠的,不会丢数据
    ——————————————————————————————————
    第二个问题,没看出什么不对来呀,这样试试
    procedure TServerFrmMain.Button1Click(Sender: TObject);
    var
    i: integer;
    ActClient: PClient;
    RecThread: TIdPeerThread;
    NewCommBlock: TCommBlock;
    begin
    try
    for i := 0 to Clients.LockList.Count - 1 do
    begin
    NewcommBlock.Command := cMessage;
    NewcommBlock.MyUserName := 'system';
    NewcommBlock.Msg := 'system test';
    NewcommBlock.ReceiverName := ''; 
    ActClient := Clients.LockList.Items[i];
    RecThread := ActClient.Thread;
    finally//这里
    Clients.UnlockList;
    end;
    RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);
    end;
    end;
    另外是不是客户端那边有问题?
      

  11.   

    当点击上面的群发按钮后,当有新的客户连接到SERVER时,
    procedure TServerFrmMain.ServerConnect(AThread: TIdPeerThread);
    var
      NewClient: PClient;
      NewCommBlock: TCommBlock;
    begin
      GetMem(NewClient, SizeOf(TClient));
      NewClient.DNS         := AThread.Connection.Socket.Binding.PeerIP;
      NewClient.Connected   := Now;
      NewClient.LastAction  := NewClient.Connected;
      NewClient.Thread      :=AThread;
      AThread.Data:=TObject(NewClient);
    //  Clients.UnlockList;
      try
        Clients.LockList.Add(NewClient);//执行到这句,SERVER没有效果!
      finally
        Clients.UnlockList;
      end;
    end;
    CLIENT显示连接,但是收、发消息都无效,看来还是TThreadList的问题,TThreadList是线程安全的应该没有同步等方面的安全问题,搞不清问题在哪里!!!
      

  12.   

    问题已找到:
    问题还是出现在TThreadList上面,
    procedure TServerFrmMain.Button1Click(Sender: TObject);
    var
    i: integer;
    ActClient: PClient;
    RecThread: TIdPeerThread;
    NewCommBlock: TCommBlock;
    begin
    try
    for i := 0 to Clients.LockList.Count - 1 do//这句,每次循环一个对象,都会EnterCriticalSection 一次,这样就会导致程序不可以继续运行,
    改为with Clients.LockList DO 这样就会保证只执行一次EnterCriticalSection !begin
    NewcommBlock.Command := cMessage;
    NewcommBlock.MyUserName := 'system';
    NewcommBlock.Msg := 'system test';
    NewcommBlock.ReceiverName := ''; 
    ActClient := Clients.LockList.Items[i];//此处改为ActClient := Items[i];
    RecThread := ActClient.Thread;
    finally//这里
    Clients.UnlockList;
    end;
    RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);
    end;
    end;
    通过查看TThreadlist的源码,然后自定义一个TMYThreadList类,为跟踪使用!这个问题其实大家很容易犯的,如果不看源码或跟踪一下,不容易找到答案的,希望与大家分享一下!
      

  13.   

    我最近研究了一阵indy,以前用socketserver ,对indy还是很陌生。针对以前我用socket实现的功能不知道如何用indy实现,(或是根本不能实现)功能如下:客户端1发出消息 A  服务器接受消息后向 客户端2,3.. 发送消息B客户端2,3...接受消息B后处理相应的过程。借楼主的宝地。呵呵,大家多多讨论讨论啊。
      

  14.   

    好了把indy的FTP和TCP都研究了一下,总算有点小成果,拿来与大家分享:
    我定义一个record
      TMyMsg = record    iType : integer;   // 操作类型: 1 :登录  2:改变状态  3:发送信息  ...
        UserName : String[255];
        Pwd : String[255];
        RecName : String[255];
        sMsg : String[255];
        iFile : integer;
        sFileName : String[255];
        iSize : int64;
        sIP  : String[255];
        ... //根据自己需要加
        istat : smallint;   // 用户状态: 0 :正常  1:隐身  2:忙碌  3:离开...   9 : 离线
        SendTime : String[50];    //登录返回值 : -1:用户名或密码错误  0:登录成功  1:已经登录   9 :异常每次发送和接收都是这个record,那样你只要判断iType值就可以进行各种处理了,目前我做的基本聊天功能都实现了,就差像MSN或者QQ那样的在线、隐身、忙碌那样的图标了,哪位兄弟有给我发一个啊,感谢感谢 :)  [email protected]