unit f_Main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, IdAntiFreezeBase, IdAntiFreeze, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, Buttons, ComCtrls;
Const
// jede Datei wird in mehere Stücke a folgende Größe zerlegt
cFileSplitSize : Longint = 20*1024;
// Bytes = 20 KB
// Trennzeichen was bei der Kommunikation mit dem Server benutzt wird
cSplitChar :
String = '
|';
type
TfrmMainClient =
class(TForm)
gb_Server: TGroupBox;
Ed_ServerIP: TEdit;
Label1: TLabel;
Label2: TLabel;
ed_Port: TEdit;
TcpCon: TIdTCPClient;
IdAntiFreeze1: TIdAntiFreeze;
gb_File: TGroupBox;
ed_File: TEdit;
sb_FindFile: TSpeedButton;
OpenDlg: TOpenDialog;
cmd_Send: TBitBtn;
pBar_SendProgress: TProgressBar;
lab_SendProgress: TLabel;
lab_SendSpeedText: TLabel;
lab_Speed: TLabel;
procedure sb_FindFileClick(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure cmd_SendClick(Sender: TObject);
private
{ Private-Deklarationen }
procedure HideSendComponents;
procedure ShowSendComponents;
function checkValues : Boolean;
public
{ Public-Deklarationen }
iFileSize : Longint;
end;
var
frmMainClient: TfrmMainClient;
implementation
{$R *.DFM}
// Datei die verschickt werden soll suchen
procedure TfrmMainClient.sb_FindFileClick(Sender: TObject);
begin
// Wenn kein Startverzeichnis gesetzt ist
if OpenDlg.InitialDir = '
'
then
// setzen wir das Startverzeichnis auf das Anwendungsverzeichnis
OpenDlg.InitialDir := ExtractFilePath(Application.ExeName);
// OpenFileDialog ausführen
if OpenDlg.Execute
then begin
ed_File.Text := OpenDlg.FileName;
end;
end;
// Alle Komponenten die zum Anzeigen des Sendevorgangs benötigt werden einblenden
procedure TfrmMainClient.ShowSendComponents;
begin
frmMainClient.Height := 226;
lab_SendProgress.Visible := true;
lab_SendSpeedText.Visible := true;
lab_Speed.Visible := true;
pBar_SendProgress.Visible := true;
end;
// Alle Komponenten die zum Anzeigen des Sendevorgangs benötigt werden ausblenden
procedure TfrmMainClient.HideSendComponents;
begin
lab_SendProgress.Visible := false;
lab_SendSpeedText.Visible := false;
lab_Speed.Visible := false;
pBar_SendProgress.Visible := false;
frmMainClient.Height := 190;
end;
procedure TfrmMainClient.FormShow(Sender: TObject);
begin
// Beim Start des Programms Sende-Komponenten ausblenden
HideSendComponents;
end;
// alle Angaben die zum Versenden der Datei benötigt werden, auf Gültigkeit überprüfen
function TfrmMainClient.checkValues: Boolean;
Var iTmp : Longint;
begin
result := true;
// Ist eine Server-IP angegeben ?
if Length(trim(Ed_ServerIP.Text)) = 0
then begin
Messagedlg('
Bitte tragen Sie die IP-Adresse des Servers ein !',mtInformation,[mbok],0);
Ed_ServerIP.SetFocus;
result := false;
exit;
end;
// Handelt es sich bei der Port-Angabe um einen ganzzahligen Wert ?
iTmp := StrToIntDef(ed_Port.text,-1);
if iTmp = -1
then begin
Messagedlg('
Bitte tragen Sie eine gültige Portnummer ein !',mtInformation,[mbok],0);
ed_Port.SetFocus;
result := false;
exit;
end;
// überprüfen, ob die Datei die verschickt werden soll existiert
if not FileExists(ed_File.Text)
then begin
Messagedlg('
Die angegebene Datei existiert nicht, bitte wählen Sie eine Datei aus!',mtInformation,[mbok],0);
ed_File.SetFocus;
result := false;
exit;
end;
end;
procedure TfrmMainClient.cmd_SendClick(Sender: TObject);
Var fs : TFileStream;
// Zum Lesen der Datei
tmpMs : TMemoryStream;
// temporärer Speicherstream zum Splitten der Datei, ab bestimmter Grösse
iTmpSize : Longint;
// Zähler um sich zu merken, wieviel Bytes schon gebuffert/gesendet wurden wurden
iNextSize : Longint;
// Byte-Anzahl die gelesen werden sollen
bError : Boolean;
// Bool-Schalter für Fehlererkennung
sMsgToSvr :
String;
// Nachricht für den Server
iSendTime : Cardinal;
// Zeitmesser auch nachher zum lesen
iTimeDiff : Cardinal;
// Var zum Zeit-Differenz berechnen
BytesperSek : Double;
sCmd :
String;
begin
// als erstes die Usereingaben prüfen
if not checkValues
then exit;
// als erstes versuchen die Datei zu öffnen, so das niemand mehr in diese Datei schreiben kann
try
fs := TFileStream.Create(ed_File.Text,fmOpenRead
or fmShareDenyWrite);
except
MessageDlg(ed_File.Text+'
kann nicht geöffnet werden ! '+#10#13
+'
Wahrscheinlich ist diese Datei von einer anderen Anwendung geöffnet !',
mtError,[mbok],0);
exit;
end;
// Verbindung zum Server herstellen
TcpCon.Disconnect;
TcpCon.Host := Ed_ServerIP.text;
TcpCon.Port := StrToIntDef(ed_Port.Text,9876);
// Versuchen eine Verbindung zum Server herzustellen
try
TcpCon.Connect(5000);
// max. 5 Sek. um die Verbindung zum Server herzustellen
except
Messagedlg('
Es konnte keine Verbindung zum Server: '+Ed_ServerIP.text+'
auf Port: '+ed_Port.Text+'
hergestelt werden!',
mtError,[mbok],0);
exit;
end;
if TcpCon.Connected
then begin
// Übertragungskomponenten anzeigen
ShowSendComponents;
// jetzt muss der Server natürlich wissen wieviele Bytes vom Client kommen,
// und wie die Datei heisst
sMsgToSvr := inttostr(fs.size)+cSplitChar+ExtractFileName(ed_File.Text);
// Nachricht zum Server schicken
TcpCon.WriteLn(sMsgToSvr);
// Server ist bereit zum Empfangen und die Verbindung besteht jetzt anfangen
// die Datei zu Senden
tmpMS := TMemoryStream.Create;
try
// Gesamtgrösse der Datei merken
iFileSize := fs.Size;
// Bufferzähler auf Null u. Error auf false
iTmpSize := 0;
bError := false;
// Stream Position wieder auf Anfang setzen (nur zur Sicherheit)
fs.Position := 0;
// Solange nicht alle Daten im versendet wurden, diese Stückweise versenden
while (iTmpSize < iFileSize)
and (
not bError)
do begin
tmpMs.clear;
// Anwenung etwas Zeit zur Nachrichten-Verarbeitung geben
Application.ProcessMessages;
iSendTime := GetTickCount;
try
// als ersten berechnen wie viel Bytes zum Senden noch da sind
iNextSize := iFileSize - iTmpSize;
// Wenn die Byte Anzahl > der FileSplitSize ist, dann muss weiter gesplittet werden
if iNextSize > cFileSplitSize
then
iNextSize := cFileSplitSize;
iTmpSize := iTmpSize + tmpMs.CopyFrom(fs,iNextSize);
TcpCon.OpenWriteBuffer;
TcpCon.WriteStream(tmpMS,true,true);
TcpCon.CloseWriteBuffer;
// Wenn die Übertragung im Lan über Delphi getestet wird, bitte folgendes Sleep
// aktivieren, das verlangsamt zwar die Übertragung, aber ansonsten gibt es
// bei der Berechnung der Sendegeschwindigkeit, divion 0 error
sleep(25);
// im realen Betrieb auskommentieren
// Zeit die fürs Senden gebraucht wurde ausrechnen
iTimeDiff := GetTickCount - iSendTime;
// Fortschrittsanzeige aktualisieren
pBar_SendProgress.Position := Round(iTmpSize/iFileSize*100);
pBar_SendProgress.Repaint;
// aktuelle Geschwindigkeit ausrechnen
try
BytesperSek := round(tmpMs.Size/1024/iTimeDiff*1000);
except
BytesperSek :=0;
end;
// Geschwindigkeit anzeigen
lab_Speed.Caption := FormatFloat('
0.00',BytesperSek)+ '
KB/Sek.';
lab_Speed.Repaint;
except
bError := true;
end;
end;
// Bestätigung vom Server lesen
try
sCmd := TcpCon.ReadLn(#$A,7500);
except
sCmd := '
TimeOut-Error';
end;
// Verbindung trennen
TcpCon.Disconnect;
finally
tmpMs.Clear;
FreeAndNil(tmpMs);
end;
HideSendComponents;
// War die Übertragung der DAtei erfolgreich ?
if (
not bError)
and (sCmd = '
FILEOK')
then
Messagedlg('
Datei wurde erfolgreich versendet!',mtInformation,[mbok],0)
else
Messagedlg('
Fehler beim versenden der Datei!',mtError,[mbok],0)
end;
end;
end.