如何实现,网上只找到采用UDP协议的....有用TCP的吗?

解决方案 »

  1.   

    //如果在如今互连网环境中做P2P恐怕不太现实的,因为很多网络运营商提供的IP都是不透明的,也就是说在外部得不到承认,因此建议使用QQ的通讯模式,下面我写了一个程序希望帮的上忙。
    我使用了服务器中转的方法,在一个程序中模拟双方通过服务器通讯。
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, IdLogDebug, IdLogStream, IdLogBase, IdLogFile,
      IdBlockCipherIntercept, IdIOHandlerThrottle, IdServerIOHandlerSocket,
      IdServerIOHandler, IdSSLOpenSSL, IdIOHandlerSocket, IdIOHandler,
      IdIOHandlerStream, IdTCPServer, IdIntercept, IdCompressionIntercept,
      IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, StdCtrls,
      ExtCtrls, IdThreadMgr, IdThreadMgrDefault;const
      CMD_MSG=1001;
      CMD_FILE=1002;
    type
      TClientInfo=class(TObject)
      public
        ClientID:String[26];
        Thread :Pointer;
      end;
      TFileInfo=record
        FileName:String[125];
        FileSize:Integer;
      end;
      TIdTCPClientReadMsgEvent=procedure(IdTCPClient:TIdTCPClient;FromID,Msg:String)of object;
      TIdTCPClientReadFileEvent=procedure(IdTCPClient:TIdTCPClient;FromID,FileName:String;FileSize:Integer)of object;  
      TClientThread=class(TThread)
      private
        FHost: String;
        FPort: Integer;
        FIdTCPClient:TIdTCPClient;
        FRegName: String;
        FOnReadFile: TIdTCPClientReadFileEvent;
        FOnReadMsg: TIdTCPClientReadMsgEvent;
        procedure SetHost(const Value: String);
        procedure SetPort(const Value: Integer);
        procedure SetRegName(const Value: String);
        procedure SetOnReadFile(const Value: TIdTCPClientReadFileEvent);
        procedure SetOnReadMsg(const Value: TIdTCPClientReadMsgEvent);
        procedure DoOnReadFile(FromID:String);
        procedure DoOnReadMsg(FromID:String);    
      public
        constructor Create;
        destructor Destroy;override;
        procedure Execute;override;
        procedure Start;
        procedure SendMessage(ClientID,Msg:String);
        procedure SendFile(ClientID,FileName:String);
        property IdTCPClient:TIdTCPClient read FIdTCPClient;
        property RegName:String read FRegName write SetRegName;
        property Host:String read FHost write SetHost;
        property Port:Integer read FPort write SetPort;
        property OnReadMsg:TIdTCPClientReadMsgEvent read FOnReadMsg write SetOnReadMsg;
        property OnReadFile:TIdTCPClientReadFileEvent read FOnReadFile write SetOnReadFile;
      end;
      
      TForm1 = class(TForm)
        IdTCPServer1: TIdTCPServer;
        MsgMemo: TMemo;
        SendMsgBtn: TButton;
        SendFileBtn: TButton;
        Button1: TButton;
        Button2: TButton;
        procedure IdTCPServer1Execute(AThread: TIdPeerThread);
        procedure IdTCPServer1Connect(AThread: TIdPeerThread);
        procedure IdTCPServer1Disconnect(AThread: TIdPeerThread);
        procedure IdTCPClient2Connected(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure SendMsgBtnClick(Sender: TObject);
        procedure SendFileBtnClick(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
        Client1,Client2:TClientThread;
        procedure ClientOnReadMsg(TCPC:TIdTCPClient;FromID,Msg:String);
        procedure ClientOnReadFile(TCPC:TIdTCPClient;FromID,FileName:String;FileSize:Integer);
        procedure SendBuffer(FromID,ClientID:String;PBuffer:PChar;DataLen:Integer);
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
    var
      ReceiverID:String;
      DataLen:Integer;
      PBuffer:PChar;
    begin
      try
        with AThread,Connection do
        begin
          ReceiverID:=ReadLn;
          DataLen:=ReadInteger;
          GetMem(PBuffer,DataLen);
          ReadBuffer(PBuffer^,DataLen);
          SendBuffer(TClientInfo(Data).ClientID,ReceiverID,PBuffer,DataLen);
        end;
      except
        on E:Exception do
        begin
          AThread.Stop;
        end;
      end;
    end;procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
    begin
      with AThread,Connection do
      begin
        Data:=TClientInfo.Create;
        with TClientInfo(Data) do
        begin
          ClientID:=ReadLn;
          Thread:=AThread;
        end;
      end;
    end;procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);
    begin
      with AThread do
      begin
        TClientInfo(Data).Free;
        Data:=nil;
      end;
    end;procedure TForm1.SendBuffer(FromID,ClientID: String; PBuffer: PChar; DataLen: Integer);
    var
      i:Integer;
    begin
      try
        with IdTCPServer1.Threads.LockList do
        begin
          for i:=0 to Count-1 do
          begin
            if TClientInfo(TIdPeerThread(Items[i]).Data).ClientID=ClientID then Break;
          end;
          if i<Count then
          begin
            try
              with TIdPeerThread(Items[i]).Connection do
              begin
                WriteLn(FromID);
                WriteBuffer(PBuffer^,DataLen,True);
              end;
            except
              TIdPeerThread(Items[i]).Stop;
            end;
          end;
        end;
      finally
        IdTCPServer1.Threads.UnlockList;
        FreeMem(PBuffer);
      end;
    end;procedure TForm1.IdTCPClient2Connected(Sender: TObject);
    begin
    end;{ TClientThread }constructor TClientThread.Create;
    begin
      FreeOnTerminate:=True;
      FIdTCPClient:=TIdTCPClient.Create(nil);
      inherited Create(True);
    end;destructor TClientThread.Destroy;
    begin
      FIdTCPCLient.Disconnect;
      FIdTCPClient.Free;
      inherited;
    end;procedure TClientThread.DoOnReadFile(FromID:String);
    var
      FI:TFileInfo;
    begin
      FIdTCPClient.ReadBuffer(FI,SizeOf(FI));
      if Assigned(FOnReadFile) then FOnReadFile(FIdTCPClient,FromID,FI.FileName,FI.FileSize);
    end;
      

  2.   

    procedure TClientThread.DoOnReadMsg(FromID:String);
    var
      ReadLen:Integer;
      Msg:String;
    begin
      FIdTCPClient.ReadBuffer(ReadLen,SizeOf(ReadLen));
      SetLength(Msg,ReadLen);
      FIdTCPClient.ReadBuffer(Msg[1],ReadLen);
      if Assigned(FOnReadMsg) then FOnReadMsg(FIdTCPClient,FromID,Msg);
    end;procedure TClientThread.Execute;
    var
      CMDID:Integer;
      FromID:String;
    begin
      with FIdTCPClient do
      begin
        Connect;
        if Connected then WriteLn(RegName);
        while not Terminated and Connected do
        begin
          FromID:=ReadLn;
          ReadBuffer(CMDID,SizeOf(CMDID));
          case CMDID of
            CMD_FILE:DoOnReadFile(FromID);
            CMD_MSG:DoOnReadMsg(FromID);
          end;
        end;
      end;
    end;procedure TClientThread.SendFile(ClientID, FileName: String);
    var
      DataLen,CMDID:Integer;
      FS:TFileStream;
      FI:TFileInfo;
    begin
      with FIdTCPClient do
      begin
        if Connected then
        begin
          FS:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyNone);
          try
            FI.FileName:=ExtractFileName(FileName);
            FI.FileSize:=FS.Size;
            WriteLn(ClientID);
            CMDID:=CMD_FILE;
            DataLen:=SizeOf(CMDID)+SizeOf(FI)+FI.FileSize;
            WriteInteger(DataLen);
            OpenWriteBuffer;
            WriteBuffer(CMDID,SizeOf(CMDID));
            WriteBuffer(FI,SizeOf(FI));
            WriteStream(FS);
            CloseWriteBuffer;
          finally
            FS.Free;
          end;
        end;
      end;
    end;procedure TClientThread.SendMessage(ClientID, Msg: String);
    var
      MsgLen,DataLen,CMDID:Integer;
    begin
      with FIdTCPClient do
      begin
        if Connected then
        begin
          WriteLn(ClientID);
          MsgLen:=Length(Msg);
          CMDID:=CMD_MSG;
          DataLen:=SizeOf(CMDID)+SizeOf(MsgLen)+MsgLen;
          WriteInteger(DataLen);      
          OpenWriteBuffer;
          WriteBuffer(CMDID,SizeOf(CMDID));      
          WriteBuffer(MsgLen,SizeOf(MsgLen));
          WriteBuffer(Msg[1],MsgLen);
          CloseWriteBuffer;
        end;
      end;
    end;
    procedure TClientThread.SetHost(const Value: String);
    begin
      FHost := Value;
    end;
    procedure TClientThread.SetOnReadFile(
      const Value: TIdTCPClientReadFileEvent);
    begin
      FOnReadFile := Value;
    end;procedure TClientThread.SetOnReadMsg(
      const Value: TIdTCPClientReadMsgEvent);
    begin
      FOnReadMsg := Value;
    end;procedure TClientThread.SetPort(const Value: Integer);
    begin
      FPort := Value;
    end;procedure TClientThread.SetRegName(const Value: String);
    begin
      FRegName := Value;
    end;procedure TClientThread.Start;
    begin
      with FIdTCPClient do
      begin
        Host:=FHost;
        Port:=FPort;
      end;
      Resume;  
    end;procedure TForm1.FormCreate(Sender: TObject);
    begin
      Client1:=TClientThread.Create;
      Client1.OnReadMsg:=ClientOnReadMsg;
      Client1.OnReadFile:=ClientOnReadFile;  
      Client1.Host:='127.0.0.1';
      Client1.Port:=1981;
      Client1.RegName:='Client One';
      Client1.Start;
      Client2:=TClientThread.Create;
      Client2.OnReadMsg:=ClientOnReadMsg;
      Client2.OnReadFile:=ClientOnReadFile;
      Client2.Host:='127.0.0.1';
      Client2.Port:=1981;
      Client2.RegName:='Client Two';
      Client2.Start;
    end;procedure TForm1.ClientOnReadFile(TCPC: TIdTCPClient; FromID,FileName: String;
      FileSize: Integer);
    var
      FS:TFileStream;
    begin
      FS:=TFileStream.Create('d:\'+FileName,fmCreate or fmShareDenyNone);
      try
        TCPC.ReadStream(FS,FileSize);
        MsgMemo.Lines.Add(FromID+' send file:'+FileName+' and save to d:\')
      finally
        FS.Free;
      end;
    end;procedure TForm1.ClientOnReadMsg(TCPC: TIdTCPClient; FromID,Msg: String);
    begin
      MsgMemo.Lines.Add(FromID+' said: '+Msg);
    end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      Client1.Terminate;
      Client2.Terminate;  
    end;procedure TForm1.SendMsgBtnClick(Sender: TObject);
    begin
      Client1.SendMessage('Client Two','Test SendMessage');
    end;procedure TForm1.SendFileBtnClick(Sender: TObject);
    begin
      Client1.SendFile('Client Two','c:\haohao.jpg');
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      Client2.SendMessage('Client One','Test SendMessage');
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
      Client2.SendFile('Client One','c:\haohao.jpg');
    end;end.