我知道是什么问题,因为我也发生过类似的错误
主要是服务器端接收的问题,在服务器端的ThreadExecute过程里,每一个AThread是一个独立的Thread,所以你要为每一个AThread单独设立相关变量,不能使用一个公用变量,不然就混了,你可以用一个动态数组管理AThread及其相关变量.

解决方案 »

  1.   

    FClient.Port:=60606;
    ---------------------------是在同一台机器上测试出现这个错误的吗?是的话把这句话删除,不可能两个程序都绑定这个端口。
      

  2.   

    服务器端主程序:
    procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
    var
    DoP:TSocketProcesser;
    begin
    DoP:=TSocketProcesser.Create(AThread);
    Athread.Data:=Dop;
    end;procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);begin
    TSocketProcesser(AThread.Data).Free;
    AThread.Data:=Nil;
    end;procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
    begin
    TSocketProcesser(AThread.Data).Process;
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
    IF IdTCPServer1.Active then
    begin
    IdTCPServer1.Active:=False;
    Button1.Caption:='启动服务';
    end
        else
        begin
        IdTCPServer1.Active:=True;
        Button1.Caption:='中止服务';
        end;
    end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
    IdTCPServer1.Active:=False;
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
    Memo1.Lines.Clear;
    end;end.
    调用的单元文件:
    procedure TSocketProcesser.Branch;
    begin
    case Rev.ID of
    0:BuildFile;
    1:Pass;
    2:FileTransport;
    3:
    begin
    UnMapViewOfFile(FileMapPointer);//关闭文件
    Form1.Memo1.Lines.Add(FN+','+TimetoStr(Now())+'结束传输');
    end;
    end;
    end;procedure TSocketProcesser.BuildFile;
    var
    FileName:String[250];
    PS,PD:PByte;
    FH1,FH2:THandle;
    size:DWord;
    begin
    PS:=TempPointer;
    Inc(PS,32);
    PD:=@FileName;
    move(PS^,PD^,Rev.Len);
    FN:=FileName;
    size:=Rev.F1;//得到文件长度
    FH1:=FileCreate('Files\'+FileName);
    FileClose(FH1);
    FH1:=FileOpen('Files\'+FileName,fmOpenreadWrite);
    FH2:=CreateFileMapping(FH1,nil,Page_ReadWrite,0,size,nil);
    CloseHandle(FH1);
    FileMapPointer:=MapViewOfFile(FH2,File_Map_All_Access,0,0,size);
    FileSize:=size;//
    CloseHandle(FH2);
    Form1.Memo1.Lines.Add(FileName+',长度'+inttostr(FileSize)+','+TimetoStr(Now())+'开始传输');
    Echo(1);
    end;
    procedure TSocketProcesser.Pass;//索取数据报
    begin
    Snd.F1:=Rev.F1+1;//下一个数据报
    Snd.F2:=Rev.F2;
    Echo(2);
    end;
    procedure TSocketProcesser.FileTransport;
    var
    TempFileMapPointer,PB:PByte;
    begin
    TempFileMapPointer:=FileMapPointer;
    PB:=PRev;
    Inc(TempFileMapPointer,Rev.F3);
    Inc(PB,32);
    move(PB^,TempFileMapPointer^,Rev.Len);
    IF Rev.F1<Rev.F2 then//请求下一个数据报
    Pass
    else//如果相等,说明已经接收完毕
    Echo(3);
    end;constructor TSocketProcesser.Create(AThread:TidPeerThread);
    begin
    inherited Create();
    AOne:=AThread;
    ReceivedCounter:=32;//首先要接收32个字节
    HeaderFinished:=False;
    BodyFinished:=False;
    PushTransporting:=False;
    RemainBytes:=0;
    PRev:=@Rev;
    PSnd:=@Snd;
    TempPointer:=PRev;end;
    procedure TSocketProcesser.Process;
    var
    Bytes:Integer;
    begin
    IF ReceivedCounter=0 then
    exit;
    IF RemainBytes>0 then//上次还有字节没收取
        begin
        ReceivedCounter:=ReceivedCounter-RemainBytes;
        IF ReceivedCounter>0 then//接收剩余字节后数据报尚未完成接收
        begin
        Bytes:=RemainBytes;//接收剩余
        RemainBytes:=0;
        end
            else
            begin
                IF ReceivedCounter=0 then//剩余字节刚好接收完成
                begin
                Bytes:=RemainBytes;
                RemainBytes:=0;
                IF HeaderFinished then
                BodyFinished:=True
                else
                    begin
                    HeaderFinished:=True;//如果头完成就是体完成,否则只是头完成
                    PushTransporting:=True;
                    end;
                end
                    else
                    begin   //剩余字节超过本数据报大小,产生数据粘连
                    Bytes:=ReceivedCounter+RemainBytes;
                    RemainBytes:=RemainBytes-Bytes;//完成本数据报后剩余字节
                    IF HeaderFinished then
                    BodyFinished:=True
                        else
                            begin
                            HeaderFinished:=True;//如果头完成就是体完成,否则只是头完成
                            PushTransporting:=True;
                            end;
                    end;
            end;
         AOne.Connection.ReadBuffer(TempPointer^,Bytes);
         Inc(TempPointer,Bytes);
         IF (Rev.Len=0) and HeaderFinished then//只要头
         begin
         HeaderFinished:=False;
         PushTransporting:=False;
         TempPointer:=PRev;
         ReceivedCounter:=32;//准备下一个头
         Branch;//分支处理
         end
            else
            begin
                IF PushTransporting then //正在传输body
                begin
                PushTransporting:=False;
                ReceivedCounter:=Rev.Len;
                end
                else
                    IF BodyFinished then
                    begin
                    TempPointer:=PRev;
                    HeaderFinished:=False;
                    BodyFinished:=False;
                    ReceivedCounter:=32;//准备下一个头
                    Branch;//分支处理
                    end        end;     end
         else
            begin
            Try
            RemainBytes:=AOne.Connection.ReadFromStack(True,15000,True);
            Except
            exit;
            end;
            end;end;procedure TSocketProcesser.Echo(Option: Word);
    begin
    Snd.ID:=Option;
    Snd.Len:=0;
    AOne.Connection.Socket.Send(PSnd^,32);
    end;
      

  3.   

    请问如何动态管理AThread及其相关变量
      

  4.   

    我知道了,你也是从网上下的那个多线程传输文件的源码吧
    我用那个试过了,多文件或多客户端传输时有问题,我就自己另写了一个
    你先定义一个结构,里面包含该线程需要用到的数据,比如用户名,文件名,线程指针等,然后在程序里定义一个上面结构的数组,每新增一个连接就增加一个这样的结构数据,连接断开,就删除该结构数据
    如这样:type
      PClient   = ^TClient;
      TClient   = record  // Object holding data of client (see events)
                    DNS,
                    Name,
                    Path            : String[255];            { Hostname }
                    MP              : PByte;                 {File Map Pointer}
                    Thread          : Pointer;               { Pointer to thread }
                    ReceiveSize     : Dword;
                    Len             : DWord;
                    FN,TFN          : string[255];
                    FileSize        : Dword;
                    isComplete      : integer;
                  end;程序里这样定义:var
    Clients         : TThreadList;新增连接时:
    var
      NewClient        : PClient;
      MsgString        : string[255];
      Snd              : TCommBlock;
      PPn              : PByte;
      RecThread        : TIdPeerThread;
    begin
      { Create a client object }
      GetMem(NewClient, SizeOf(TClient));
    { Assign its default values }
      NewClient.DNS         := AThread.Connection.LocalName;
      NewClient.Name        := 'Logging In';
      NewClient.ListLink    := lbClients.Items.Count;
      NewClient.Connected   := Now;
      NewClient.LastAction  := NewClient.Connected;
      NewClient.isComplete  := 0;
    { Assign the thread to it for ease in finding }
      NewClient.Thread      := AThread;
    { Assign it to the thread so we can identify it later }
      AThread.Data := TObject(NewClient);
    { Add it to the clients list }
      try
        Clients.LockList.Add(NewClient);
      finally
        Clients.UnlockList;
      end; //把每个连接的客户加入客户管理集断开连接时这样:
    var
      ActClient : PClient;
      FP        : PByte;
      _Name1,
      _DNS1     : string[255];
    begin
    { Retrieve Client Record from Data pointer }
      ActClient := PClient(AThread.Data);
      FP        := ActClient.MP;
      _Name1    := ActClient.Name;
      _DNS1     := ActClient.DNS ;
    { Remove Client from the Clients TThreadList }
      try
        
        Clients.LockList.Remove(ActClient);
      finally
        Clients.UnlockList;
      end;
    { Free the Client object }
      FreeMem(ActClient);
      AThread.Data := nil;连接后ThreadExecute过程里这样
    { Get the clients package info }
        ActClient            := PClient(AThread.Data);
        RecThread            := ActClient.Thread;     // get client-thread out of it
        { Get the Data sent from the client }
        RecThread.Connection.ReadBuffer(CommBlock, 1072);//读取客户传来的头数据
        ActClient.LastAction := Now;
              ActClient.ReceiveSize          := 0;
              //------------------------------
              ActClient.FN       := CommBlock.Name;
              ActClient.TFN      := inttostr(yearof(Now))+inttostr(monthof(Now))+inttostr(dayof(Now))+
                                    inttostr(hourof(Now)) +inttostr(minuteof(Now)) +inttostr(secondof(Now))+
                                    inttostr(MilliSecondOf(Now))+inttostr(ActClient.ListLink) + ExtractFileExt(ActClient.FN);
              ActClient.Path     := CommBlock.Path;
              ActClient.FileSize := CommBlock.Len;//得到文件长度
              ActClient.isComplete  := 1;
              FileName           := ActClient.TFN;
              FilePath           := FileTransferPathTemp ;
              size               := CommBlock.Len;//得到文件长度
              FH1:=FileCreate(FilePath + '\'+FileName);
              FileClose(FH1);
              FH1:=FileOpen(FilePath + '\' + FileName,fmOpenreadWrite);
              FH2:=CreateFileMapping(FH1,nil,Page_ReadWrite,0,size,nil);
              CloseHandle(FH1);          ActClient.MP := MapViewOfFile(FH2,File_Map_All_Access,0,0,size);//文件指针          CloseHandle(FH2);
      

  5.   

    是根据Connect事件和Disconnect来判断的吗
      

  6.   

    是,每个连接断开都会触发ondisconnect事件
      

  7.   

    上面这段代码运行时:TCommBlock,lbClients,  NewClient.Connected   := Now,
      NewClient.LastAction  := NewClient.Connected;提示没有指定,是要添加什么单元吗.
    新增连接时:
    var
      NewClient        : PClient;
      MsgString        : string[255];
      Snd              : TCommBlock;
      PPn              : PByte;
      RecThread        : TIdPeerThread;
    begin
      { Create a client object }
      GetMem(NewClient, SizeOf(TClient));
    { Assign its default values }
      NewClient.DNS         := AThread.Connection.LocalName;
      NewClient.Name        := 'Logging In';
      NewClient.ListLink    := lbClients.Items.Count;
      NewClient.Connected   := Now;
      NewClient.LastAction  := NewClient.Connected;
      NewClient.isComplete  := 0;
    { Assign the thread to it for ease in finding }
      NewClient.Thread      := AThread;
    { Assign it to the thread so we can identify it later }
      AThread.Data := TObject(NewClient);
    { Add it to the clients list }
      try
        Clients.LockList.Add(NewClient);
      finally
        Clients.UnlockList;
      end; //把每个连接的客户加入客户管理集
      

  8.   

    TCommBlock是一个自定义的结构,就是一个数据包
    lbClients是一个LABEL,
    .Connected和.LastAction就是上面的结构里的一个字段啊
    因为程序代码太长了,我没办法给你全部发过来,以上这些都是自定义的,上面的代码只是给你一个思路,具体的你还要自己根据实际情况定义
      

  9.   

    没有解决,谁有完整的例子发给我一份:[email protected]