//客户端
unit UntClt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
StdCtrls, UntGlb, IdGlobal, ExtCtrls, ImgList, jpeg, WinSock, IdIPWatch;
type
TForm1 = class (TForm)
stat1: TStatusBar;
img1: TImage;
lbl1: TLabel;
btn1: TButton;
chk1: TCheckBox;
edt1: TEdit;
btn2: TButton;
btn3: TButton;
btn4: TButton;
btn5: TButton;
grp1: TGroupBox;
lst1: TListBox;
idtcpclnt1: TIdTCPClient;
BalloonHint1: TBalloonHint;
il1: TImageList;
dlgOpen1: TOpenDialog;
ProgressBar1: TProgressBar;
btnCancle: TButton;
IdIPWatch1: TIdIPWatch;
procedure btn1Click(Sender: TObject);
procedure chk1Click(Sender: TObject);
procedure idtcpclnt1Disconnected(Sender: TObject);
procedure btn2Click(Sender: TObject);
procedure idtcpclnt1Connected(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure btn5Click(Sender: TObject);
procedure btn3Click(Sender: TObject);
procedure btn4Click(Sender: TObject);
procedure WMMOVE( var msg: TMessage); message WM_MOVE;
procedure WMUSERMSG( var msg: TMessage); message WM_USERMSG;
procedure ShowProgressBar(Visible: Boolean);
procedure btnCancleClick(Sender: TObject);
private
{ Private declarations }
ComputerName: string ;
public
{ Public declarations }
UserBreakAll: Boolean;
end ;
TFileThread = class (TThread)
private
// CB: TDataPack;
protected
procedure Execute; override ;
end ;
TMonitorThread = class (TThread)
protected
procedure Execute; override ;
end ;
var
Form1: TForm1;
FileThread: TFileThread;
MonitorThread: TMonitorThread;
AllowDisconnectedEvent: Boolean = False;
function SendARP(Destip, scrip: DWORD; pmacaddr: PDWORD;
VAR phyAddrlen: DWORD): DWORD; stdcall ; external ' iphlpapi.dll ' ;
implementation
{ $R *.dfm }
function GetMacFromIP(IP: AnsiString): AnsiString;
type
Tinfo = array [ 0 .. 7 ] of Byte;
var
dwTargetIP: DWORD;
dwMacAddress: array [ 0 .. 1 ] of DWORD;
dwMacLen: DWORD;
dwResult: DWORD;
X: Tinfo;
stemp: AnsiString;
iloop: integer;
begin
dwTargetIP : = Inet_Addr(PAnsiChar(IP));
dwMacLen : = 6 ;
dwResult : = SendARP(dwTargetIP, 0 , @dwMacAddress[ 0 ], dwMacLen);
case dwResult of
NO_ERROR:
begin
// ShowMessage( ' 查到 ' );
X : = Tinfo(dwMacAddress);
for iloop : = 0 to 5 do
begin
stemp : = stemp + inttohex(X[iloop], 2 );
end ;
Result : = stemp;
end ;
ERROR_BAD_NET_NAME:
Result : = ' 目标IPv4地址无法送达(Windows Vista 及以后版本错误) ' ;
ERROR_BUFFER_OVERFLOW:
Result : = ' PhyAddrLen参数小于6(Windows Vista 及以后版本错误) ' ;
ERROR_GEN_FAILURE:
Result : = ' 目标IPv4地址无法送达(Windows Server 2003及之前版本错误) ' ;
ERROR_INVALID_PARAMETER:
Result : = ' pMacAddr或PhyAddrLen参数是一个NULL指针(Windows Server 2003及之前版本错误) ' ;
ERROR_INVALID_USER_BUFFER:
Result : = ' PhyAddrLen参数为零(Windows Server 2003及之前版本错误) ' ;
// ERROR_NOT_FOUND:Result : = ' 非INADDR_ANY的IP地址(IPv4地址为0.0.0.0)(Windows Vista 错误) ' ;
ERROR_NOT_SUPPORTED:
Result : = ' 本机操作系统不支持该函数 ' ;
else
Result : = ' 未知 ' ;
end ;
end ;
function GetWindowsVersionString: AnsiString;
var
VI: TOSVersionInfoA;
begin
VI.dwOSVersionInfoSize : = SizeOf(TOSVersionInfoA);
if GetVersionExA(VI) then
with VI do
Result : = Trim(Format( ' %d.%d build %d %s ' , [dwMajorVersion,
dwMinorVersion, dwBuildNumber, szCSDVersion]))
else
Result : = '' ;
end ;
function GetWindowsVersion: String; // 读取操作系统版本
var
AWin32Version: Extended;
os: string ;
begin
os : = ' Windows ' ;
AWin32Version : = StrtoFloat(Format( ' %d.%d ' , [Win32MajorVersion,
Win32MinorVersion]));
if Win32Platform = VER_PLATFORM_WIN32s then
Result : = os + ' 32 '
else if Win32Platform = VER_PLATFORM_WIN32_WINDOWS then
begin
if AWin32Version = 4.0 then
Result : = os + ' 95 '
else if AWin32Version = 4.1 then
Result : = os + ' 98 '
else if AWin32Version = 4.9 then
Result : = os + ' Me '
else
Result : = os + ' 9x '
end
else if Win32Platform = VER_PLATFORM_WIN32_NT then
begin
if AWin32Version = 3.51 then
Result : = os + ' NT 3.51 '
else if AWin32Version = 4.0 then
Result : = os + ' NT 4.0 '
else if AWin32Version = 5.0 then
Result : = os + ' 2000 '
else if AWin32Version = 5.1 then
Result : = os + ' XP '
else if AWin32Version = 5.2 then
Result : = os + ' 2003 '
else if AWin32Version = 6.0 then
Result : = os + ' Vista '
else if AWin32Version = 6.1 then
Result : = os + ' 7 '
else
Result : = os;
end
else
Result : = os + ' ?? ' ;
Result : = Result + ' ' + GetWindowsVersionString;
end ;
procedure TForm1.btn1Click(Sender: TObject);
begin
close;
end ;
procedure TForm1.btn2Click(Sender: TObject);
var
i: integer;
begin
if dlgOpen1.Execute(Handle) then
begin
for i : = 0 to dlgOpen1.Files.Count - 1 do
lst1.Items.add(dlgOpen1.Files[i]);
end ;
grp1.Caption : = GroupText + Format(FileListString, [lst1.Count]);
end ;
procedure TForm1.btn3Click(Sender: TObject);
begin
lst1.Clear;
grp1.Caption : = GroupText + Format(FileListString, [ 0 ]);
end ;
procedure TForm1.btn4Click(Sender: TObject);
begin
lst1.DeleteSelected;
grp1.Caption : = GroupText + Format(FileListString, [lst1.Count]);
end ;
procedure TForm1.btn5Click(Sender: TObject);
var
DlgText: string ;
begin
if idtcpclnt1.Connected then
begin
if lst1.Count > 0 then
begin
DlgText : = Format(DlgSendFileText, [lst1.Count]);
if Application.MessageBox(PChar(DlgText), ' 发送提示 ' ,
MB_OKCANCEL + MB_ICONQUESTION) = IDOK then
begin
ShowProgressBar(True);
FileThread : = TFileThread.Create(True);
FileThread.FreeOnTerminate : = True;
FileThread.Start;
end ;
end
else
ShowMessage(DlgSelectFile);
end
else
ShowMessage(DlgNoConnected);
end ;
procedure TForm1.btnCancleClick(Sender: TObject);
begin
UserBreakAll : = True;
end ;
procedure TForm1.chk1Click(Sender: TObject);
begin
idtcpclnt1.Host : = edt1.Text;
if chk1.Checked then
begin
try
Application.ProcessMessages;
idtcpclnt1.Connect;
AllowDisconnectedEvent : = True;
stat1.Panels[ 1 ].Text : = StaConnected;
except
ShowMessage(DlgConnectFailed);
end ;
end
else
begin
AllowDisconnectedEvent : = False;
idtcpclnt1.Disconnect;
end ;
chk1.Checked : = idtcpclnt1.Connected;
end ;
procedure TForm1.FormCreate(Sender: TObject);
var
n: Cardinal;
Name: array [ 0 .. MAX_COMPUTERNAME_LENGTH] of Char;
begin
n : = MAX_COMPUTERNAME_LENGTH + 1 ;
GetComputerName(name, n);
ComputerName : = string (Name);
MonitorThread : = TMonitorThread.Create(True);
MonitorThread.FreeOnTerminate : = True;
MonitorThread.Start;
end ;
procedure TForm1.idtcpclnt1Connected(Sender: TObject);
var
bbuf: TIdBytes;
buf: TDataPack;
begin
bbuf : = nil ;
FillChar(buf, SizeOf(buf), '' );
buf.Command : = cmdSetName;
StrPCopy(buf.ClientInfo.ClientName ,ComputerName);
StrPCopy(buf.ClientInfo.ClientOS,GetWindowsVersion);
StrPCopy(buf.ClientInfo.ClientACTIP ,GetMacFromIP(IdIPWatch1.LocalIP));
bbuf : = RawToBytes(buf, SizeOf(buf));
idtcpclnt1.IOHandler.Write(bbuf);
end ;
procedure TForm1.idtcpclnt1Disconnected(Sender: TObject);
begin
stat1.Panels[ 1 ].Text : = StaDisconnected;
chk1.Checked : = False;
end ;
procedure TForm1.ShowProgressBar(Visible: Boolean);
begin
ProgressBar1.Visible : = Visible;
btnCancle.Visible : = Visible;
end ;
procedure TForm1.WMMOVE( var msg: TMessage);
begin
// inherited ;
// if Assigned(frmProgress) then
// frmProgress.Position : = poMainFormCenter;
end ;
procedure TForm1.WMUSERMSG( var msg: TMessage);
begin
case msg.WParam of
1 :
ShowMessage(Format(DlgFileSendOk, [msg.LParam]));
2 :
stat1.Panels[ 1 ].Text : = string (PChar(msg.LParam));
3 :
ProgressBar1.Position : = msg.LParam;
4 :
ProgressBar1.Max : = msg.LParam;
5 :
idtcpclnt1.OnDisconnected(Self);
6 :
ShowMessage(DlgExcept);
7 :
ShowProgressBar(False);
end ;
end ;
{ TFileThread }
procedure TFileThread.Execute;
var
FileName: string ;
buf: TDataPack;
bbuf: TIdBytes;
i, j, SendTimes, RemainLen, h, FileLen, SentFilesNum,
ClientReadedBytes: integer;
begin
try
Form1.UserBreakAll : = False;
SentFilesNum : = 0 ;
for i : = 0 to Form1.lst1.Count - 1 do
begin
if Form1.UserBreakAll then
Break;
FileName : = Form1.lst1.Items[i];
// frmProgress.lbl1.Caption : = FileName;
// frmProgress.pb1.Position : = 0 ;
PostMessage(Form1.Handle, WM_USERMSG, 2 , integer(PChar(FileName)));
PostMessage(Form1.Handle, WM_USERMSG, 3 , 0 );
h : = FileOpen(FileName, fmOpenRead);
if h > 0 then
begin
try
FileLen : = GetFileSize(h, nil );
SendTimes : = FileLen div SEND_BUF;
RemainLen : = FileLen mod SEND_BUF;
// frmProgress.pb1.Max : = FileLen;
PostMessage(Form1.Handle, WM_USERMSG, 4 , FileLen);
FillChar(buf.ClientInfo, SizeOf(buf.ClientInfo), '' );
buf.Command : = cmdSendFile;
StrPCopy(buf.FileName,ExtractFileName(FileName));
buf.FileSize : = FileLen;
buf.Flags : = 0 ; // 新建
for j : = 1 to SendTimes do
begin
if Form1.UserBreakAll then
Break;
if not Form1.idtcpclnt1.Connected then
Break;
ClientReadedBytes : = FileRead(h, buf.FileData, SEND_BUF);
buf.ReadBytes : = ClientReadedBytes;
bbuf : = nil ;
bbuf : = RawToBytes(buf, SizeOf(buf));
Form1.idtcpclnt1.IOHandler.Write(bbuf);
buf.Flags : = 1 ; // 续传
// frmProgress.pb1.Position : = j * SEND_BUF;
PostMessage(Form1.Handle, WM_USERMSG, 3 , j * SEND_BUF);
end ;
if RemainLen > 0 then
begin
if not Form1.idtcpclnt1.Connected then
Break;
ClientReadedBytes : = FileRead(h, buf.FileData, RemainLen);
buf.ReadBytes : = ClientReadedBytes;
bbuf : = nil ;
bbuf : = RawToBytes(buf, SizeOf(buf));
Form1.idtcpclnt1.IOHandler.Write(bbuf);
PostMessage(Form1.Handle, WM_USERMSG, 3 , FileLen);
end ;
finally
FileClose(h);
end ;
if ( not Form1.UserBreakAll) then
inc(SentFilesNum);
end ;
end ;
PostMessage(Form1.Handle, WM_USERMSG, 7 , 0 );
PostMessage(Form1.Handle, WM_USERMSG, 1 , SentFilesNum);
if Form1.idtcpclnt1.Connected and Form1.UserBreakAll then
begin
bbuf : = nil ;
buf.Command : = cmdUserbreak;
bbuf : = RawToBytes(buf, SizeOf(buf));
Form1.idtcpclnt1.IOHandler.Write(bbuf);
end ;
except
PostMessage(Form1.Handle, WM_USERMSG, 7 , 0 );
PostMessage(Form1.Handle, WM_USERMSG, 6 , 0 );
AllowDisconnectedEvent : = False;
Form1.idtcpclnt1.Disconnect;
Terminate;
end ;
end ;
{ TMonitorThread }
procedure TMonitorThread.Execute;
begin
while not Terminated do
begin
if not Form1.idtcpclnt1.Connected then
if AllowDisconnectedEvent then
begin
AllowDisconnectedEvent : = False;
PostMessage(Form1.Handle, WM_USERMSG, 5 , 0 );
end ;
Sleep( 100 );
end ;
end ;
end .
//公共单元
unit UntGlb;
interface
uses
Messages,Windows, SysUtils,Classes ;
const
WM_USERMSG = WM_USER + 1002 ;
WM_USERFILE = WM_USER + 1003 ;
ADD_LIST = 0 ;
DEL_LIST = 1 ;
UPD_STA = 2 ;
SHOW_R = 3 ;
SEND_BUF = 1024 * 20 ;
REV = ' REV ' ;
IniFileName = ' Server.ini ' ;
type
TCommand = (cmdSetName,cmdSendFile,cmdUserbreak,cmdGetClientInfo);
TClientInfo = packed record
ClientName : array [ 0 .. 49 ] of Char;
ClientIP : array [ 0 .. 14 ] of Char;
ClientID : array [ 0 .. 9 ] of Char;
ClientACTIP : array [ 0 .. 17 ] of Char;
ClientOS : array [ 0 .. 49 ] of Char;
ClientStatus : array [ 0 .. 9 ] of Char;
ReceivedFileName : array [ 0 .. 255 ] of Char;
ReceivedPersent,
ReceivedFileSize : Cardinal;
Flags : Integer;
IdleTime : TTime;
Isbusy : Boolean;
end ;
TDataPack = packed record
Flags : Integer;
FileSize,
ReadBytes : Cardinal;
Command : TCommand;
ClientInfo : TClientInfo;
FileName : array [ 0 .. 255 ] of Char;
FileData : array [ 0 ..SEND_BUF - 1 ] of Byte;
end ;
resourcestring
MainFormCaption = ' Indy10.5.5 IdTcpServer Demo ' ;
StringsObjectName = ' object ' ;
GroupText = ' 发送文件列表 ' ;
FileListString = ' (%d个文件) ' ;
DlgCreateIniFailed = ' 创建配置文件失败,请检查磁盘空间 ' ;
DlgIniFileBreak = ' 配置文件损坏,重新创建失败 ' ;
DlgIniNotExists = ' 配置文件不存在 ' ;
DlgIniBusy = ' 配置文件被占用 ' ;
DlgSendFileText = ' 您确定要发送列表中的%d个文件吗? ' ;
DlgSendFileCaption = ' 发送提示 ' ;
DlgFileSendOk = ' %d个文件发送成功 ' ;
DlgSelectFile = ' 请选择待发送的文件 ' ;
DlgNoConnected = ' 未连接服务器 ' ;
DlgFileExists = ' 文件%s已存在,要替换吗? ' ;
DlgLogOk = ' 日志保持成功 ' ;
DlgLogFailed = ' 日志保存失败 ' ;
DlgConnectFailed = ' 连接被拒绝,可能服务器没有开启 ' ;
DlgExcept = ' 服务器端异常断开,文件传输中止! ' ;
StaInitText = ' 服务器未开启 ' ;
StaText = ' 客户端连接数:%d个 ' ;
StaConnected = ' 已链接到服务器 ' ;
StaDisconnected = ' 已从服务器断开 ' ;
StaServerStart = ' 服务器开启 ' ;
StaServerClose = ' 服务器关闭 ' ;
StaReceivedPersent = ' 接收文件:%s--(%u%%) ' ;
LogTxt = ' ------服务器操作日志------ ' + # 13 + # 10 ;
LogServerStart = ' 【服务器开启--%s】 ' ;
LogServerClose = ' 【服务器关闭--%s】 ' ;
LogClientdisConnected = ' 【客户端:%s,%s】从服务器断开--%s ' ;
LogClientConnected = ' 【客户端:%s,%s】连接到服务器--%s ' ;
LogReceiveFile = ' 【客户端:%s】正在发送文件: %s(大小:%u字节)--%s ' ;
LogReceiveFileOk = ' 【客户端:%s】发送的文件: %s 接收完毕,保存在REV子目录下--%s ' ;
LogUerBreakSend = ' 【客户端:%s】用户终止文件: %s 传送--%s ' ;
LogClientStateSleep = ' 空闲 ' ;
LogClientStateBusy = ' 数据传输中 ' ;
LogClientTimeOut = ' 客户端空闲超时,断开连接... ' ;
bhBalloonHint = ' 欢迎使用,双击显示界面 ' ;
bhBalloonTitle = ' Indy10.5.5Demo ' ;
dlgInputBoxCpt = ' 客户端连接数设置 ' ;
dlgInputBox = ' 最大连接数 ' ;
implementation
end .