我知道是什么问题,因为我也发生过类似的错误
主要是服务器端接收的问题,在服务器端的ThreadExecute过程里,每一个AThread是一个独立的Thread,所以你要为每一个AThread单独设立相关变量,不能使用一个公用变量,不然就混了,你可以用一个动态数组管理AThread及其相关变量.
主要是服务器端接收的问题,在服务器端的ThreadExecute过程里,每一个AThread是一个独立的Thread,所以你要为每一个AThread单独设立相关变量,不能使用一个公用变量,不然就混了,你可以用一个动态数组管理AThread及其相关变量.
---------------------------是在同一台机器上测试出现这个错误的吗?是的话把这句话删除,不可能两个程序都绑定这个端口。
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;
我用那个试过了,多文件或多客户端传输时有问题,我就自己另写了一个
你先定义一个结构,里面包含该线程需要用到的数据,比如用户名,文件名,线程指针等,然后在程序里定义一个上面结构的数组,每新增一个连接就增加一个这样的结构数据,连接断开,就删除该结构数据
如这样: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);
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; //把每个连接的客户加入客户管理集
lbClients是一个LABEL,
.Connected和.LastAction就是上面的结构里的一个字段啊
因为程序代码太长了,我没办法给你全部发过来,以上这些都是自定义的,上面的代码只是给你一个思路,具体的你还要自己根据实际情况定义