V tomto díle si ukážeme, jak poslat soubor po počítačové síti.
V jednom z minulých dílu jsme se učili udělat chat v Delphi za pomocí komponent ServerSocket a ClientSocket. Jestliže nemáte žádné zkušenosti s těmito komponentami, doporučoval bych článek si přečíst. Začnu asi trochou teorie, jak by nám to posílání mělo fungovat. Nejprve si na klientském počítači vybereme soubor, který budeme chtít odeslat. Po tom, co si soubor vybereme, připojíme se k našemu serveru a odešleme mu název souboru a jeho velikost. Jakmile budou základní informace o souboru odeslané, stačí už jen odeslat soubor. Obrázek klienta:
Ještě je tam komponenta OpenDialog. U Button2 a Button3 nastavte Enabled na False. A teď zdrojový kód:
….
private
Soubor_Stream:TFileStream; //vytvoření proměnné, přes kterou budeme odesílat soubor
public
….
Další pomocné proměnné:
var
Form1: TForm1;
soubor: string; //uložení filename souboru
velikost :int64; //velikost souboru
Když stiskneme tlačítko Otevři:
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then begin
if Trim(OpenDialog1.FileName) <> "" then begin
if fileexists(OpenDialog1.FileName) then begin
soubor := ExtractFileName(OpenDialog1.FileName); //nastavíme název souboru
Label2.Caption := soubor;
Soubor_Stream := TFileStream.Create(soubor,fmOpenRead);// otevřeme soubor a uložíme do streamu
Button2.enabled := True;
end;
end;
end;
end;
Tlačítko Připojit:
procedure TForm1.Button2Click(Sender: TObject);
begin
ClientSocket1.ClientType := ctNonBlocking;
ClientSocket1.Port := 123456; // nastavíme port
ClientSocket1.Address := Edit1.Text; // nastavíme IP adresu
ClientSocket1.Active := True;
end;
Když se připojíme:
procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Button3.enabled := True;
end;
Když se odpojíme:
procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Button1.Enabled := True;
Button2.Enabled := False;
Button3.Enabled := False;
end;
Jestliže nám přichází příkazy ze serveru, tak se na ně podíváme:
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
zprava:string; //pomocná proměnná
begin
zprava := socket.ReceiveText; //přiřadíme text, který přišel
if zprava = "NAME ??" then begin //jestli je zpráva „NAME ??“
socket.SendText("NAME = "+ label2.Caption); //odešleme jméno souboru
end;
If zprava = "SIZE ??" then begin //jestli je zpráva „SIZE ??“
socket.SendText("SIZE = " + IntToStr(Soubor_Stream.Size)); //odešleme velikost souboru
end;
end;
A poslední tlačítko – Odeslat:
procedure TForm1.Button3Click(Sender: TObject);
begin
ClientSocket1.Socket.SendStream(Soubor_Stream);
end;
Tímto jsme vlastně odeslali soubor na server. Teď si ukážeme, jak server vypadá:
Snad jedinou použitou komponentou je tam memo. U něj si nastavme vlastnost ReadOnly na True. Zdrojový kód serveru:
Proměnné:
var
Form1: TForm1;
FStream: TFileStream; //proměnná na ukládání souboru
cekam_na_jmeno, cekam_na_velikost:boolean; //pomocné proměnné
jmenoSouboru:string; //jméno souboru
velikost_soub:int64; //velikost souboru
Po vytvoření formuláře:
procedure TForm1.FormCreate(Sender: TObject);
begin
ServerSocket1.ServerType := stNonBlocking; //spojení bude neblokující
ServerSocket1.Port := 123456; //port
ServerSocket1.Active := True; //zapneme server
cekam_na_jmeno := false; //inicializace proměnných
cekam_na_velikost := true; //inicializace proměnných
end;
Když se zapne server:
procedure TForm1.ServerSocket1Listen(Sender: TObject;
Socket: TCustomWinSocket);
begin
Memo1.Lines.Add("Naslouchám......."); // server ohlásí, že je připraven
end;
Při připojení klienta:
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Memo1.Lines.Add("Připojen: "+socket.LocalHost+"("+socket.RemoteAddress+")"); //vložíme do mema informace, kdo se k nám připojil
socket.SendText("NAME ??"); //odešleme dotaz
cekam_na_jmeno := true; //změníme pomocnou proměnou
end;
A teď asi nejdelší a nejsložitější část (když přijdou nějaká data na server):
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
velikost: integer; //velikost příchozích dat
buffer: Pointer; //pomocný ukazatel
zprava:string; //pomocná proměnná k zjištění, co přišlo za příkaz
begin
if cekam_na_jmeno then begin// jestliže čekáme na jméno souboru
zprava := Socket.ReceiveText; //do proměnné vložíme, co nám přišlo
if leftStr(zprava,7) = "NAME = " then begin //jestliže to bude jméno, pak…
jmenoSouboru := rightStr(zprava,Length(zprava)-7);//"vycucneme" název souboru z řetězce
FStream := TFileStream.Create(jmenoSouboru,fmCreate or fmShareDenyWrite); //vytvoříme stream, kam se budou zapisovat části souboru
cekam_na_jmeno := false;
cekam_na_velikost := true;
socket.SendText("SIZE ??"); //odešleme příkaz
Memo1.Lines.Add("Jméno souboru: "+jmenosouboru); // vypíšeme do mema jméno souboru
end;
end;
if cekam_na_velikost then begin // jestliže čekáme na velikost souboru
zprava := Socket.ReceiveText; //do proměnné vložíme, co nám přišlo
if leftStr(zprava,7) = "SIZE = " then begin //jestliže zpráva bude začínat na „SIZE = “
velikost_soub := StrToInt(RightStr(zprava,Length(zprava)-7)); //vycucneme velikost souboru
cekam_na_velikost := false; //přestaneme čekat na velikost souboru
Memo1.Lines.Add("Velikost souboru: "+IntToStr(velikost_soub)+" b");
end;
end;
velikost := socket.ReceiveLength;//kolik dat jsme příjali
GetMem(buffer,velikost);//alokujeme paměť
try
socket.ReceiveBuf(buffer^,velikost); //do bufferu uložíme to, co nám přišlo
FStream.Write(buffer^, velikost); // a zapíšeme do souboru
finally
FreeMem(buffer); //uvolníme paměť
end;
if velikost_soub = FStream.Size then begin
Memo1.Lines.Add("Posílání souboru ukončeno");
ServerSocket1.Active := false; // vypneme server a tím docílíme odpojení klienta
Memo1.Lines.Add("Server neaktivní"); //zapíšeme do mema
ServerSocket1.Active := true;// zapneme server
FStream.Free;// uvolníme proměnnou
end;
end;
Toto je celé. Snažil jsem se popsat vše, co by mohlo být nesrozumitelné, ale myslím si, že teď to snad pochopí i průměrně zkušený programátor v Delphi.
Prosím, nepište do komentářů, že například tento kód není správný:
socket.ReceiveBuf(buffer^,velikost); //do bufferu uložíme to, co nám přišlo
Mělo tam být, že do pointeru buffer se uloží adresa na data, ale chtěl jsem to udělat tak, aby to opravdu pochopil skoro každý. To je pro tento díl vše.