给你贴一个通讯单元,很好用
// 功能模块:uSocketCommon.PAS
// 功能描述:下面是客户端和服务器端都要用到的公共单元uSocketCommon.PAS。
// 该单元是客户端应用程序和服务器端应用程序的核心部分,应用
// 程序中的常量、类型、过程、函数等都在本单元中声明。
// 程序员: Jan
// 创建日期:2002/04/27
unit uSocketCommon;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
FileCtrl, StdCtrls, ScktComp, ComCtrls;
const
{ 下面是一组应用程序中用到的字符串常量 }
sConnectedOK = '建立连接';
sConnecting = '正在连接...';
sDisconnectedOK = '断开连接';
sSaving = '正在发送...';
sLoading = '正在接收...';
sConnectError = '连接失败!请检查相关设置';
sMessageBoxCaption = '消息';
sPercentFmt = '已经完成 %D%%'; { 用于显示数据传输完成的百分比 }
{ 下面是动词列表:
前缀是vc的动词表由客户端发出;前缀是vs的动词由服务器端发出。 }
vcNone = 8000; { 无效的动词 }
vsNone = 8000; { 无效的动词 }
vcCancel = 9001; { 取消操作 }
vsEchoCancel = 9002; { 响应取消 }
vcFail = 9003; { 操作失败 }
vsEchoFail = 9004; { 响应失败 }
vsFail = 9005; { 操作失败 }
vcSave = 1001; { 请求发送,即保存到服务器中 }
vsReadyToSave = 1002; { 接收和保存文件准备就绪 }
vcSaveInfo = 1003; { 要保存文件的信息 }
vsSaveInfoOK = 1004; { 正确收到保存文件的信息 }
vcFirstBuf = 1005; { 发送第一个包 }
vsFirstBufOK = 1006; { 正确收到第一个包 }
vcCommonBuf = 1007; { 发送中间的包 }
vsCommonBufOK = 1008; { 正确收到中间的包 }
vcLastBuf = 1009; { 发送最后一个包 }
vsSaveOK = 1010; { 正确接收完毕即保存成功 }
vcLoad = 2001; { 请求接收,即从服务器装入 }
vsReadyToLoad = 2002; { 向客户端发送文件准备就绪 }
vcLoadInfo = 2003; { 需要接收文件的信息-文件名 }
vsLoadInfoOK = 2004; { 正确收到并返回文件大小 }
vcReadyToLoad = 2005; { 接收文件准备就绪 }
vsFirstBuf = 2006; { 发送第一个包 }
vcFirstBufOK = 2007; { 正确收到第一个包 }
vsCommonBuf = 2008; { 发送中间的包 }
vcCommonBufOK = 2009; { 正确收到中间的包 }
vsLastBuf = 2010; { 发送最后一个包 }
vcLoadOK = 2011; { 正确接收完毕即接收成功 }
vsLoadOK = 2012; { 接收成功 }
ServerSocketPort = $DACB; { 端口号,可任意设置,尽可能不要与其它端口号重复 }
DataLen = 512; { 数据包的最大尺寸是0.5k字节 这个值要注意,考虑网络状况差要设得小一点,在网络状况好的环境可适当设大change by wjm 2002.07.03}
LeadLen = 20; { 引导包的固定尺寸是20字节 }
{ 引导包中包括 16 个字节的身份识别代码和 4 个字节动词代码 }
SendLen = LeadLen + DataLen; { 发送包或接收包的最到尺寸是 (4096 + 20) 字节 }
type
TDataBuf = array[0..DataLen - 1] of Char; { 数据包缓存 }
TLeadBuf = array[0..LeadLen - 1] of Char; { 引导包缓存 }
TSendBuf = array[0..SendLen - 1] of Char; { 发送包或接收包缓存 }
TFileOfChar = file of Char; { 字符文件,用于接收方保存文件 }
TSocketMode = (smSave, smLoad, smNone); { 用于表示Socket当前的状态 }
TSocketData = record { 用于保存与当前Socket相关的信息 }
OnLine: Boolean; { 连接状态 }
Mode: TSocketMode; { 工作状态 }
SrcFileName: string; { 源文件名 }
DstFileName: string; { 目标文件名 }
FS: TFileStream; { 文件流 }
FSEnabled: Boolean; { 文件流状态 }
F: TFileOfChar; { 文件 }
FEnabled: Boolean; { 文件状态 }
FileSize: Integer; { 文件尺寸 }
LeftSize: Integer; { 剩余尺寸 }
ProgressBar: TProgressBar; { 进度条 }
ALabel: TLabel; { 进度标签 }
end;
PSocketData = ^TSocketData; { 类型指针,类型为TSocketData类型 }
TSocketVerb = Integer; { 动词类型 }
{ 根据动词确定相应的文本用于登记日志 }
function VerbToString(AVerb: TSocketVerb): string;
{ 判定动词是否含有终止意图 }
function IsTerminateVerb(AVerb: TSocketVerb): Boolean;
{ 报告错误 }
procedure ShowError(AHandle: THandle; S: string);
{ 传输日志 }
procedure Log(S: string; AMemo: TMemo);
{ 重置相关数据 }
procedure ResetSocketData(var P: PSocketData);
{ 新建Socket的相关数据,返回指针 }
function NewSocketData: PSocketData;
{ 将得到的包分解成为引导包和数据包 }
procedure ExtractBuf(Buf: TSendBuf; BufSize: Integer; var LBuf: TLeadBuf; var DBuf: TDataBuf);
{ 分解引导包得到引导包中包含的动词 }
function ExtractVerb(LBuf: TLeadBuf): TSocketVerb;
{ 根据指定的动词初始化需要发送的包 }
procedure MakeVerbBuf(AVerb: TSocketVerb; var Buf: TSendBuf;
var SendSize: Integer);
{ 将数据包写入要发送的包中 }
procedure MakeSendBuf(DataBuf: TDataBuf; Count: Integer;
var SendBuf: TSendBuf; var SendSize: Integer);
{ 服务器端响应和处理客户端动词,这里的处理是服务器端程序的核心部分 }
procedure ServerEchoForVerb(AVerb: TSocketVerb; DataBuf: TDataBuf; DL: Integer;
var SendBuf: TSendBuf; var SendSize: Integer;
AServerSocket: TCustomWinSocket);
{ 客户端响应和处理服务器端动词,这里的处理是客户端程序的核心部分 }
procedure ClientEchoForVerb(AVerb: TSocketVerb; DataBuf: TDataBuf; DL: Integer;
var SendBuf: TSendBuf; var SendSize: Integer;
AClientSocket: TClientSocket);
implementation
uses uCFunction, uClientF;
const
IDString = 'SOCKET_TEST_DEMO'; { 引导包中的身份识别串,16个字符,可用于客户端身份验证 }
LogTimeFormat = 'YYYY-MM-DD HH:MM:SS '; { 用于登记传输日志的时间格式 }
DataSubDir = 'ReceiveData'; { 服务器端接收文件保存到应用程序所在目录的子目录Data中 }
TempSubDir = 'ReceiveData'; { 客户端接收文件保存到应用程序所在目录的子目录Temp中 }
var
DataDir: string; { 服务器端保存文件的路径 }
TempDir: string; { 客户端保存文件的路径 }
{ 判定动词是否含有终止操作的意图 }
function IsTerminateVerb(AVerb: TSocketVerb): Boolean;
begin
Result := (AVerb = vcNone) or
(AVerb = vsNone) or
(AVerb = vcCancel) or
(AVerb = vsEchoCancel) or
(AVerb = vcFail) or
(AVerb = vsEchoFail) or
(AVerb = vsFail) or
(AVerb = vsSaveOK) or
(AVerb = vcLoadOK) or
(AVerb = vsLoadOK);
end;
{ 报告错误 }
procedure ShowError(AHandle: THandle; S: string);
begin
MessageBox(AHandle, PChar(S),
sMessageBoxCaption, MB_OK + MB_ICONEXCLAMATION);
end;
{ 服务器端登记数据传输日志 }
procedure Log(S: string; AMemo: TMemo);
begin
AMemo.Lines.Append(FormatDateTime(LogTimeFormat, Now) + S);
end;
{ 重置与Socket相关的数据 }
procedure ResetSocketData(var P: PSocketData);
begin
with P^ do try
Mode := smNone;
SrcFileName := '';
DstFileName := '';
if FSEnabled then try FS.Free; except end;
FSEnabled := False;
if FEnabled then try CloseFile(F); except end;
FEnabled := False;
FileSize := 0;
LeftSize := 0;
except
end;
end;
{ 新建一个数据结构,用于存放相关Socket的有关信息 }
function NewSocketData: PSocketData;
var
P: PSocketData;
begin
New(P);
with P^ do begin
Mode := smNone;
SrcFileName := '';
DstFileName := '';
FSEnabled := False;
FEnabled := False;
FileSize := 0;
LeftSize := 0;
P^.OnLine := False;
end;
Result := P;
end;
{ 分解收到的包,得到引导包和数据包 }
procedure ExtractBuf(Buf: TSendBuf; BufSize: Integer;
var LBuf: TLeadBuf; var DBuf: TDataBuf);
var
X: Integer;
begin
for X := 0 to LeadLen - 1 do LBuf[X] := Buf[X];
for X := LeadLen to BufSize - 1 do DBuf[X - LeadLen] := Buf[X];
end;
{ 分解引导包,得到动词 }
function ExtractVerb(LBuf: TLeadBuf): TSocketVerb;
var
HeadS: string[16];
VerbS: string[4];
X: Integer;
AVerb: TSocketVerb;
begin
HeadS := '';
for X := 0 to 15 do HeadS := HeadS + LBuf[X];
VerbS := '';
for X := 16 to LeadLen - 1 do VerbS := VerbS + LBuf[X];
if HeadS = IDString then
try { 身份识别串合法时才检查动词 }
AVerb := StrToInt(VerbS);
except
AVerb := vcNone; { 解析动词失败,则认为是无效动词 }
end
else
begin
AVerb := vcNone; { 身份非法则认为是无效动词 }
end;
Result := AVerb;
end;
{ 根据动词对将发送的包进行引导包部分的初始化 }
procedure MakeVerbBuf(AVerb: TSocketVerb; var Buf: TSendBuf;
var SendSize: Integer);
var
S: string;
X: Integer;
begin
S := IDString + IntToStr(AVerb);
if Length(S) = LeadLen then begin
for X := 1 to LeadLen do
Buf[X - 1] := S[X];
end;
SendSize := LeadLen;
end;
{ 将数据包写入将发送的包 }
procedure MakeSendBuf(DataBuf: TDataBuf; Count: Integer;
var SendBuf: TSendBuf; var SendSize: Integer);
var
X: Integer;
begin
for X := 0 to Count - 1 do
SendBuf[LeadLen + X] := DataBuf[X];
SendSize := LeadLen + Count;
end;
{ 根据Socket相关的信息建立保存文件信息的数据包 }
procedure MakeSaveInfoBuf(P: PSocketData; var SendBuf: TSendBuf;
var SendSize: Integer);
var
S: string;
X, Len: Integer;
begin
MakeVerbBuf(vcSaveInfo, SendBuf, SendSize);
S := P^.SrcFileName + '|' +
P^.DstFileName + '|' +
IntToStr(P^.FileSize) + '|';
Len := Length(S);
for X := 1 to Len do
SendBuf[LeadLen + X - 1] := S[X];
SendSize := LeadLen + Len;
end;
{ 根据客户端Socket的相关信息建立下载文件信息的数据包,该包不含文件大小信息 }
procedure MakeClientLoadInfoBuf(P: PSocketData; var SendBuf: TSendBuf;
var SendSize: Integer);
var
S: string;
X, Len: Integer;
begin
MakeVerbBuf(vcLoadInfo, SendBuf, SendSize);
S := P^.SrcFileName + '|' + P^.DstFileName + '|0|';
Len := Length(S);
for X := 1 to Len do
SendBuf[LeadLen + X - 1] := S[X];
SendSize := LeadLen + Len;
end;
{ 根据服务器端Socket的相关信息建立将送出文件信息的数据包,包括文件大小信息 }
procedure MakeServerLoadInfoBuf(P: PSocketData; var SendBuf: TSendBuf;
var SendSize: Integer);
var
S: string;
X, Len: Integer;
begin
MakeVerbBuf(vsLoadInfoOK, SendBuf, SendSize);
S := P^.SrcFileName + '|' +
P^.DstFileName + '|' +
IntToStr(P^.FileSize) + '|';
Len := Length(S);
for X := 1 to Len do
SendBuf[LeadLen + X - 1] := S[X];
SendSize := LeadLen + Len;
end;
{ 分解数据包,得到将保存的文件的信息,存入向相关的Socket的数据中 }
procedure ExtractSaveInfo(DataBuf: TDataBuf; var P: PSocketData);
var
S, ASrcFileName, ADstFileName, AFileSize: string;
ASize: Integer;
begin
S := DataBuf;
try
ASrcFileName := Copy(S, 1, Pos('|', S) - 1); Delete(S, 1, Pos('|', S));
ADstFileName := Copy(S, 1, Pos('|', S) - 1); Delete(S, 1, Pos('|', S));
AFileSize := Copy(S, 1, Pos('|', S) - 1);
ASize := StrToInt(AFileSize);
P^.SrcFileName := ASrcFileName;
P^.DstFileName := ADstFileName;
P^.FileSize := ASize;
except
end;
end;
{ 分解数据包,得到将要下载的文件信息,并存入相关的Socket数据中 }
procedure ExtractLoadInfo(DataBuf: TDataBuf; var P: PSocketData);
var
S, ASrcFileName, ADstFileName, AFileSize: string;
ASize: Integer;
begin
S := DataBuf;
try
ASrcFileName := Copy(S, 1, Pos('|', S) - 1); Delete(S, 1, Pos('|', S));
ADstFileName := Copy(S, 1, Pos('|', S) - 1); Delete(S, 1, Pos('|', S));
AFileSize := Copy(S, 1, Pos('|', S) - 1);
ASize := StrToInt(AFileSize);
P^.SrcFileName := ASrcFileName;
P^.DstFileName := ADstFileName;
P^.FileSize := ASize;
except
end;
end;
{ 根据传输的相关信息更新进度显示 }
procedure UpdateProgress(P: PSocketData);
var
R: Real;
N: Integer;
begin
if P^.ProgressBar.Max <= 0 then P^.ProgressBar.Max := 1; { 防止 0 作除数 }
R := P^.ProgressBar.Position / P^.ProgressBar.Max;
R := R * 100;
N := Round(R);
P^.ALabel.Caption := Format(sPercentFmt, [N]); { 进度百分比 }
end;
{ 服务器端响应和处理客户端动词}
procedure ServerEchoForVerb(AVerb: TSocketVerb; DataBuf: TDataBuf; DL: Integer;
var SendBuf: TSendBuf; var SendSize: Integer;
AServerSocket: TCustomWinSocket);
{ 参数 AVerb 是根据客户端数据包解析得到的动词;
参数 DataBuf 是得到的客户端的数据包;
参数 DL 是数据包的尺寸;
变量参数 SendBuf 用于返回响应的包;
变量参数 SendSize 用于返回响应包的尺寸;
对象参数 AServerSocket 用于表明处理当前响应的Socket。
}
var
P: PSocketData; { 用于访问Socket中的相关数据 }
ResL, L: Integer; { 局部变量 }
DBuf: TDataBuf; { 数据包 }
EchoVerb: TSocketVerb; { 响应动词 }
begin
P := AServerSocket.Data; { 指向Socket的数据 }
SendSize := 0;
if P <> nil then case AVerb of
{ 以下是异常情况下的动词响应 }
vcNone:
SendSize := 0; { 如果是无效动词,则不响应 }
vcCancel:
MakeVerbBuf(vsEchoCancel, SendBuf, SendSize); { 响应取消操作 }
vcFail:
MakeVerbBuf(vsEchoFail, SendBuf, SendSize); { 响应上传失败 }
{ 以下是服务器端接收文件时对客户端动词的响应 }
vcSave:
MakeVerbBuf(vsReadyToSave, SendBuf, SendSize); { 响应上传就绪 }
vcSaveInfo:
begin { 解析保存文件的信息,响应解析成功 }
ExtractSaveInfo(DataBuf, P);
MakeVerbBuf(vsSaveInfoOK, SendBuf, SendSize);
end;
vcFirstBuf, vcCommonBuf:
begin { 响应收到包成功 }
EchoVerb := vsFail;
if ((AVerb = vcFirstBuf) and (not P^.FEnabled)) or
((AVerb = vcCommonBuf) and (P^.FEnabled)) then
try
if AVerb = vcFirstBuf then
begin
{ 如果是第一个包则用Rewrite方式打开文件 }
P^.DstFileName := DataDir + '/' + ExtractFileName(P^.DstFileName);
AssignFile(P^.F, P^.DstFileName);
Rewrite(P^.F);
P^.FEnabled := True;
EchoVerb := vsFirstBufOK; { 响应收到第一个包 }
end
else
begin
EchoVerb := vsCommonBufOK; { 响应收到中间的包 }
end;
BlockWrite(P^.F, DataBuf, DL, ResL); { 数据写入文件 }
if ResL <> DL then EchoVerb := vsFail; { 写失败则响应失败 }
except
EchoVerb := vsFail; { 操作引发异常则响应失败 }
end;
MakeVerbBuf(EchoVerb, SendBuf, SendSize); { 构造响应包 }
end;
vcLastBuf:
begin { 收到最后一个包,成功处理后响应保存成功 }
EchoVerb := vsFail;
if P^.FEnabled then try
BlockWrite(P^.F, DataBuf, DL, ResL);
CloseFile(P^.F); { 关闭文件 }
P^.FEnabled := False;
EchoVerb := vsSaveOK;
except
EchoVerb := vsFail;
end;
MakeVerbBuf(EchoVerb, SendBuf, SendSize);
//更句用于写大文件,这步有待改进
RenameFileExtend(P^.DstFileName, 'zip');
end;
{ 以下是服务器端发送文件时对客户端动词的响应 }
vcLoad:
MakeVerbBuf(vsReadyToLoad, SendBuf, SendSize); { 向客户端发送就绪 }
vcLoadInfo:
begin { 解析文件名,创建文件流,响应文件大小 }
ExtractLoadInfo(DataBuf, P);
if FileExists(P^.SrcFileName) then try { 检查文件是否存在 }
P^.SrcFileName :=
DataDir + '/' + ExtractFileName(P^.SrcFileName);
P^.FS := TFileStream.Create(P^.SrcFileName, fmOpenRead);
P^.FSEnabled := True;
P^.FileSize := P^.FS.Size;
P^.Mode := smLoad;
P^.LeftSize := P^.FS.Size;
MakeVerbBuf(vsLoadInfoOK, SendBuf, SendSize);
MakeServerLoadInfoBuf(P, SendBuf, SendSize);
except
MakeVerbBuf(vsFail, SendBuf, SendSize);
end else begin
MakeVerbBuf(vsFail, SendBuf, SendSize);
end;
end;
vcReadyToLoad:
begin { 客户端就绪则发送第一个包 }
if P^.FSEnabled then try
case P^.LeftSize of
0: L := 0;
1..DataLen: L := P^.LeftSize;
else
L := DataLen;
end;
if L > 0 then P^.FS.ReadBuffer(DBuf, L);
P^.LeftSize := P^.LeftSize - L; { 更新剩余的数据大小 }
MakeVerbBuf(vsFirstBuf, SendBuf, SendSize);
MakeSendBuf(DBuf, L, SendBuf, SendSize);
except
MakeVerbBuf(vsFail, SendBuf, SendSize);
end else begin
MakeVerbBuf(vsFail, SendBuf, SendSize);
end;
end;
vcFirstBufOK,
vcCommonBufOK:
begin { 客户端正确收到,则继续发送剩余的包 }
if P^.FSEnabled then
try
if P^.LeftSize > DataLen then
L := DataLen
else
L := P^.LeftSize;
if L > 0 then P^.FS.ReadBuffer(DBuf, L);
P^.LeftSize := P^.LeftSize - L;
if P^.LeftSize = 0 then
MakeVerbBuf(vsLastBuf, SendBuf, SendSize)
else
MakeVerbBuf(vsCommonBuf, SendBuf, SendSize);
MakeSendBuf(DBuf, L, SendBuf, SendSize);
except
MakeVerbBuf(vsFail, SendBuf, SendSize);
end
else
begin
MakeVerbBuf(vsFail, SendBuf, SendSize);
end;
end;
vcLoadOK: MakeVerbBuf(vsLoadOK, SendBuf, SendSize); { 发送成功 }
else
SendSize := 0; { 除上述所有情况之外,则不响应 }
end;
end;
{ 客户端响应并处理服务器端的动词 }
procedure ClientEchoForVerb(AVerb: TSocketVerb; DataBuf: TDataBuf; DL: Integer;
var SendBuf: TSendBuf; var SendSize: Integer;
AClientSocket: TClientSocket);
{ 参数 AVerb 是根据服务器端数据包解析得到的动词;
参数 DataBuf 是得到的服务器端的数据包;
参数 DL 是数据包的尺寸;
变量参数 SendBuf 用于返回响应的包;
变量参数 SendSize 用于返回响应包的尺寸;
对象参数 AClientSocket 用于表明处理当前响应的Socket。
考虑到下面的响应处理与服务器端的响应处理比较相似,所以注释从简。
}
var
P: PSocketData;
DBuf: TDataBuf;
ResL, L: Integer;
EchoVerb: TSocketVerb;
begin
SendSize := 0;
P := AClientSocket.Socket.Data;
if (P <> nil) and (P^.OnLine) then
case AVerb of
vsNone,
vsEchoCancel,
vsEchoFail,
vsFail:
SendSize := 0;
vsReadyToSave:
begin
P^.FS := TFileStream.Create(P^.SrcFileName, fmOpenRead);
P^.Mode := smSave;
P^.FSEnabled := True;
P^.FileSize := P^.FS.Size;
P^.LeftSize := P^.FS.Size;
P^.ProgressBar.Min := 0; { 初始化进度条数据 }
P^.ProgressBar.Max := P^.FS.Size;
P^.ProgressBar.Position := 0;
MakeSaveInfoBuf(P, SendBuf, SendSize);
end;
vsSaveInfoOK:
begin
if P^.FSEnabled then try
case P^.LeftSize of
0: L := 0;
1..DataLen: L := P^.LeftSize;
else
L := DataLen;
end;
if L > 0 then P^.FS.ReadBuffer(DBuf, L);
P^.LeftSize := P^.LeftSize - L;
MakeVerbBuf(vcFirstBuf, SendBuf, SendSize);
MakeSendBuf(DBuf, L, SendBuf, SendSize);
P^.ProgressBar.Position := P^.ProgressBar.Position + L;
UpdateProgress(P); { 更新进度显示 }
except
MakeVerbBuf(vcFail, SendBuf, SendSize);
end else begin
MakeVerbBuf(vcFail, SendBuf, SendSize);
end;
end;
vsFirstBufOK,
vsCommonBufOK:
begin
if P^.FSEnabled then
try
if P^.LeftSize > DataLen then
L := DataLen
else
L := P^.LeftSize;
if L > 0 then P^.FS.ReadBuffer(DBuf, L);
P^.LeftSize := P^.LeftSize - L;
if P^.LeftSize = 0 then
MakeVerbBuf(vcLastBuf, SendBuf, SendSize)
else
MakeVerbBuf(vcCommonBuf, SendBuf, SendSize);
MakeSendBuf(DBuf, L, SendBuf, SendSize);
P^.ProgressBar.Position := P^.ProgressBar.Position + L;
UpdateProgress(P); { 更新进度显示 }
except
MakeVerbBuf(vcFail, SendBuf, SendSize);
end else begin
MakeVerbBuf(vcFail, SendBuf, SendSize);
end;
end;
vsSaveOK:
SendSize := 0;
vsReadyToLoad:
MakeClientLoadInfoBuf(P, SendBuf, SendSize);
vsLoadInfoOK:
begin
ExtractSaveInfo(DataBuf, P);
MakeVerbBuf(vcReadyToLoad, SendBuf, SendSize);
end;
vsFirstBuf,
vsCommonBuf:
begin
if ((AVerb = vsFirstBuf) and (not P^.FEnabled)) or
((AVerb = vsCommonBuf) and (P^.FEnabled)) then
try
if AVerb = vsFirstBuf then
begin
P^.DstFileName :=
TempDir + '/' + ExtractFileName(P^.DstFileName);
AssignFile(P^.F, P^.DstFileName);
Rewrite(P^.F);
P^.FEnabled := True;
P^.ProgressBar.Min := 0;
P^.ProgressBar.Max := P^.FileSize;
P^.ProgressBar.Position := 0;
EchoVerb := vcFirstBufOK;
end
else
begin
EchoVerb := vcCommonBufOK;
end;
BlockWrite(P^.F, DataBuf, DL, ResL);
if ResL <> DL then
MakeVerbBuf(vcFail, SendBuf, SendSize)
else
MakeVerbBuf(EchoVerb, SendBuf, SendSize);
P^.ProgressBar.Position := P^.ProgressBar.Position + DL;
UpdateProgress(P);
except
MakeVerbBuf(vcFail, SendBuf, SendSize)
end
else
begin
MakeVerbBuf(vcFail, SendBuf, SendSize)
end;
end;
vsLastBuf:
begin
EchoVerb := vcFail;
if P^.FEnabled then try
BlockWrite(P^.F, DataBuf, DL, ResL);
CloseFile(P^.F);
P^.FEnabled := False;
EchoVerb := vcLoadOK;
P^.ProgressBar.Position := P^.ProgressBar.Position + DL;
UpdateProgress(P);
except
EchoVerb := vcFail;
end;
MakeVerbBuf(EchoVerb, SendBuf, SendSize)
end;
vsLoadOK:
begin
SendSize := 0;
end;
else
SendSize := 0;
end;
end;
{ 根据动词确定相应的文本用于登记日志 }
function VerbToString(AVerb: TSocketVerb): string;
var
S: string;
begin
case AVerb of
vcSave: S := '开始接收';
vcLastBuf: S := '接收成功';
vcLoad: S := '开始发送';
vcLoadOK: S := '发送成功';
vcCancel: S := '取消操作';
vcFail: S := '操作失败';
vcNone: S := '收到非法数据';
else
S := '';
end;
Result := S;
end;
initialization
{ 检查相关目录是否存在,如果不存在则建立,以防止文件操作失败。}
DataDir := ExtractFilePath(Application.ExeName) + DataSubDir;
TempDir := ExtractFilePath(Application.ExeName) + TempSubDir;
if not DirectoryExists(DataDir) then ForceDirectories(DataDir);
if not DirectoryExists(TempDir) then ForceDirectories(TempDir);
end.