//服务端:
const //transmit用的参数
TF_USE_KERNEL_APC = $20;
//命令类型
CMD_CapScreen = 2000;
CMD_CapVideo = 2001;
CMD_CapAudio = 2002;
CMD_GetSystemInfo = 2003;
CMD_TransmitFiles = 2004;
//通用数据传输包体封装type //每个完整数据的头描述
TPacketHeader = packed record
PacketCMD : Word; //包类型
DataLength : Word; //包体长度
IsCompressed : Boolean; //包体是否为压缩数据
end;
TBytes = array [0..65535] of Byte;
TPacketBody = packed record
Data : TBytes;
end;
//完整的数据包
TPacketInfo = packed record
Header : TPacketHeader;
Body : TPacketBody;
end;
//文件发送包
TFileSendPacket = packed record
FileName : array [0..127] of Char;
FileSize : LongWord;
StartWritePositon : LongWord;
hFile : THandle;
end;
function TServerClientSocket.TransFile(FileName: string;StartWritePositon:LongWord): Boolean;
var hFile : THandle;
NumberOfByteSend : LongWord;
Block:PBlock;
PacketInfo: TPacketInfo;
FileSendPacket : TFileSendPacket;
AFileName : string[128];
TransmitFileBuffers : TTransmitFileBuffers;
begin if not FileExists(FileName) then
begin
Result := False;
Exit;
end;
hFile := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
//如果文件打开错误,则退出
if hFile = INVALID_HANDLE_VALUE then
begin
Result := False;
Closehandle(hFile);
Exit;
end;
//得到需要传输的字节数
NumberOfByteSend := windows.GetFileSize(hFile, nil) - StartWritePositon;
if NumberOfByteSend <= 0 then
begin
Closehandle(hFile);
Exit;
end;
Block := AllocBlock;
Block.Data.Event := seFileSend;
Block.Data.Overlapped.Offset := StartWritePositon;
AFileName := ExtractFileName(FileName);
FillChar(PacketInfo,SizeOf(TPacketInfo),0);
FillChar(FileSendPacket,SizeOf(TFileSendPacket),0);
Move(AFileName[1],FileSendPacket.FileName,length(AFileName));
FileSendPacket.FileSize := NumberOfByteSend;
FileSendPacket.StartWritePositon := StartWritePositon;
FileSendPacket.hFile := hFile;
PacketInfo.Header.PacketCMD := CMD_TransmitFiles;
PacketInfo.Header.DataLength := Sizeof(TFileSendPacket);
PacketInfo.Header.IsCompressed := False;
Move(FileSendPacket,PacketInfo.Body.Data,SizeOf(TFileSendPacket));
Move(PacketInfo,Block^.Data.Buffer,SizeOf(TPacketHeader) + SizeOf(TFileSendPacket));
//传输文件前发送的包
TransmitFileBuffers.Head := @Block^.Data.Buffer[0];
TransmitFileBuffers.HeadLength := SizeOf(TPacketHeader) + SizeOf(TFileSendPacket);
//传输文件完毕后发送的包
TransmitFileBuffers.Tail := nil;
TransmitFileBuffers.TailLength := 0;
LogMsg('开始发送文件:' + FileName + ' Size=' + IntToStr(NumberOfByteSend));
//发送命令,并将文件名、继传点、需要传输的大小传递过去
if not TransmitFile(SocketHandle, hFile, NumberOfByteSend, MAX_BUFSIZE,
@Block^.Data.Overlapped, @TransmitFileBuffers, TF_USE_KERNEL_APC) then
begin
if GetLastError <> ERROR_IO_PENDING then
begin
Result := False;
Exit;
end;
end;
Result := True;
end;
//如果发送完毕,可以接收到重叠IO的返回结果 case Block^.Data.Event of
seFileSend:
begin
Block.IsUse := False;
Move(Block.Data.Buffer,PacketInfo,SizeOf(TPacketHeader) + SizeOf(TFileSendPacket));
if PacketInfo.Header.PacketCMD = CMD_TransmitFiles then
begin
FillChar(FileSendPacket,SizeOf(TFileSendPacket),0);
Move(PacketInfo.body.data,FileSendPacket,SizeOf(TFileSendPacket));
Closehandle(FileSendPacket.hFile); //发送完毕,关闭文件句柄
end;
LogMsg('文件:' + StrPas(FileSendPacket.FileName) + ' 发送完毕!');
if not PrepareRecv() then Result := RESPONSE_FAIL;
end;
seRead: 。。。。。。。
//客户端:procedure TrecvThread.Execute;
var PacketInfo : TPacketInfo;
str: string;
FileSendPacket:TFileSendPacket;
FileStream:TFileStream;
FileName :string;
RecBuf:array[0..1023] of Char;
RemainByts,RecvedBytes:Integer;
begin while (not self.Terminated ) DO
begin
cs.CheckForDisconnect(False);
if cs.ClosedGracefully then
begin
Fmm.Lines.Add('链路断开!');
self.Terminate;
end;
cs.ReadBuffer(PacketInfo.Header,SizeOf(TPacketHeader));
cs.ReadBuffer(PacketInfo.Body.Data, PacketInfo.Header.DataLength);
if PacketInfo.Header.PacketCMD = CMD_TransmitFiles then
begin
Move(PacketInfo.Body.Data,FileSendPacket,PacketInfo.Header.DataLength);
FileName := StrPas(FileSendPacket.FileName);
try
FileStream := TFileStream.Create('C:\'+ FileName, fmCreate or fmOpenWrite);
Fmm.Lines.Add('接收:' + FileName + ' Size=' + IntToStr(FileSendPacket.FileSize));
RecvedBytes := 0;
while (RecvedBytes < FileSendPacket.FileSize) do
begin
if FileSendPacket.FileSize <= 1024 then
begin
cs.ReadBuffer(RecBuf,FileSendPacket.FileSize);
RecvedBytes := FileSendPacket.FileSize;
FileStream.WriteBuffer(RecBuf,RecvedBytes);
Break;
end else begin
cs.ReadBuffer(RecBuf,1024);
RecvedBytes := RecvedBytes + 1024;
FileStream.WriteBuffer(RecBuf,1024);
RemainByts := FileSendPacket.FileSize - RecvedBytes;
if RemainByts <= 1024 then
begin
cs.ReadBuffer(RecBuf,RemainByts);
RecvedBytes := RecvedBytes + RemainByts;
FileStream.WriteBuffer(RecBuf,RemainByts);
Break;
end;
end;
end;
finally
FileStream.Free;
end;
end;
end;
end;
http://www.delphi6.com/thread-554.htm