INDY
rk7771
INDY - Internet Direct (komponenty otwarte).
1 Opis ogólny
1.1 Gniazda
1.2 Protokoły
1.3 Typy połączeń gniazdowych
2 Komponenty INDY w praktyce
2.4 TCP
2.5 UDP
2.6 Obsługa poczty - wysyłanie (SMTP) i odbieranie (POP3)
2.6.1 SMTP
2.6.2 POP3
2.7 HTTP
2.7.3 Zapis strony do pliku na dysku lokalnym
2.7.4 Niestandardowy serwer HTTP
2.7.5 Prosty serwer HTTP
2.8 FTP
2.8.6 Klient FTP
2.8.7 Serwer FTP
2.9 IdThreadComponent
2.9.8 Użycie w powiązaniu z pakietem TCP
2.10 IdIcmpClient (Internet Control Message Protocol)
2.10.9 Przykład sprawdzający dostępność adresów w całym segmencie
2.11 IdIPWatch
2.12 IdConnectionIntercept
Opis ogólny
Komponenty Internet Direct obsługują programowanie gniazdowe niskiego poziomu oraz większość powszechnie znanych protokołów internetowych. Borland, w celu zastąpienia "przestarzałych" komponentów: TCPClient czy TcpServer, zaproponował stosowanie odpowiednich komponentów Indy. Dostarcza kolekcję internetowych otwartych komponentów, które poprzednio nazywane były WinShoes (termin pochodzi od WinSock - nazwy biblioteki gniazdowej Windows).
Internet Direct (Indy) stworzone zostało przez grupę kierowaną przez Chada Howera (jest również dostępne w Kyliksie). Najnowsze wersje otwartych komponentów Indy znaleźć można pod adresem internetowym http://www.indyproject.org/ . Są to darmowe komponenty uzupełnione wieloma przykładami oraz plikami pomocy. Indy w wersji 8 rozpowszechniane było wraz z Delphi 6, w wersji 9 dostępne jest od Delphi 7. W Delphi 2005 podczas instalacji możliwy jest wybór przez użytkownika instalowanej wersji Indy (9 lub 10).
Komponenty Indy rozpoznawane są po przedrostku "Id". Pakiet INDY zawiera ponad 100 komponentów zawierających aplikacje klient-serwer TCP/IP dla rozmaitych komponentów, zawiera składniki związane z bezpieczeństwem oraz kodowaniem.
Połączenia nieblokujące - polegają na odczytywaniu danych z gniazd oraz zapisywaniu do nich w sposób asynchroniczny, co nie powoduje blokowania realizacji innych fragmentów kodu aplikacji sieciowej. Alternatywnym podejściem jest użycie połączenia blokującego, przy którym aplikacja czeka, aż odczyt lub zapis zostanie zakończony i dopiero wówczas przechodzi do wykonania następnej linii kodu.Komponenty Indy stosują połączenia blokujące co daje możliwość uproszczenia logiki programu. Operacje gniazdowe wykonywane z poziomu Indy, powinny być wykonywane za pomocą wątku albo komponentu IdAntiFreeze stanowiącego prostszą alternatywę. Serwery Indy wykorzystują architekturę wielowątkową którą sterować można za pomącą komponentów IdThreadMgrDefault oraz IdThreadMgrPool. Komponent IdThreadMgrDefault jest domyślnym komponentem, drugi obsługuje odpytywanie (ang. pooling) wątków.
Gniazda
Sercem Internetu jest Transmision Control Protokol/Internet Protokol (TCP/IP). Jest to zestaw dwóch oddzielnych protokołów zapewniających połączenie przez prywatną sieć intranetową czy internet.
Protokół TCP odpowiada za usługi transportowe wysokiego poziomu. Jest on zorientowany połączeniowo, czyli umożliwia zestawienie połączenia w którym efektywnie i niezawodnie przesyłane są dane. Połączenie to charakteryzuje się możliwością sterowania przepływem, potwierdzania odbioru, zachowania kolejności danych, kontroli błędów i przeprowadzania retransmisji. TCP organizuje również dwukierunkową współpracę między warstwą IP, a warstwami wyższymi, uwzględniając przy tym wszystkie aspekty priorytetów i bezpieczeństwa. Musi prawidłowo obsłużyć niespodziewane zakończenie aplikacji, do której właśnie wędruje datagram, musi również bezpiecznie izolować warstwy wyższe - w szczególności aplikacje użytkownika - od skutków awarii w warstwie protokołu IP. Protokół IP odpowiada za: definiowanie oraz wybór marszruty datagramów (czyli porcji danych przesyłanych w sieci) oraz określanie schematu adresowania.Każde połączenie odbywa się przez port. Port jest reprezentowany przez 16 bitową liczbę. Adres IP jest 32 bitową liczbą składającą się z czterech składników zwanych oktetami oddzielonych kropkami (np.: 127.0.0.1 jest adresem localhost-u i można go wykorzystywać przy testowaniu działania komponentów klient-serwer przy braku połączenia z internetem).
Adresy IP wraz z portami TCP określają połączenia internetowe lub gniazda. Różne aplikacje działające na tym samym zestawie komputerowym nie mogą używać tego samego gniazda (czyli tego samego portu).Niektóre porty TCP zostały zarezerwowane dla określonych protokołów i usług wysokiego poziomu.
Protokół | Port |
HTTP (Hypertext Transfer Protokol) | 80 |
FTP (File Transfer Protokol) | 21 |
SMTP (Simple Mail Transfer Protokol) | 25 |
POP3 (Post Office Protokol) | 110 |
Telnet | 23 |
Lista portów wraz z opisem dostępna jest na stronie www.iana.org/assignments/port-numbers.
Protokoły
Protokół stanowi zbiór zasad, które przestrzegane będą przez aplikacje typu klient i serwer, ustalający przepływ danych. Protokoły niskiego poziomu, w skład których wchodzą TCP/IP, implementowane są przez system operacyjny. W skład protokołów wysokiego poziomu wchodzą HTTP, FTP czy SMTP i są one zdefiniowane na stronie www.ietf.org firmy Internet Engineering Task Force. Protokoły przesyłania są na wyższym poziomie niż protokoły transmisji, ponieważ abstrahują od mechanizmu transportu zapewnionego przez TCP/IP. Dzięki tej właściwości protokoły nie są zależne od systemu operacyjnego czy sprzętu, są również niezależne od fizycznej sieci.Typy połączeń gniazdowych
- Połączenia klienta - inicjowane są przez klienta i łączą jego lokalne gniazdo ze zdalnym gniazdem serwera. Gniazda klienta określają serwer z którym się chcą połączyć poprzez podanie jego nazwy lub adresu IP wraz z portem.
- Połączenia nasłuchujące - są biernymi gniazdami serwera oczekującymi klienta. Po zgłoszeniu klienta żądania serwer tworzy nowe gniazdo przeznaczone do określonego połączenia, a następnie powraca do nasłuchiwania.
- Połączenia serwera - są połączeniami aktywowanymi przez serwer po zaakceptowaniu żądania ze strony klienta.
Komponenty INDY w praktyce
TCP
Protokół TCP (Transmision Control Protokol) jest protokołem połączeniowym, umożliwia zestawienie połączenia w którym efektywnie i niezawodnie przesyłane są dane. Zestawione połączenie charakteryzuje się możliwością sterowania przepływem, potwierdzania odbioru, zachowania kolejności danych, kontrolowania błędów oraz przeprowadzania retransmisji. Protokół TCP organizuje dwukierunkową współpracę między warstwą IP, a warstwami wyższymi Do jego cech zaliczyć można również prawidłową obsługę niespodziewanie zakończonych aplikacji otrzymujących datagram oraz bezpieczne izolowanie warstwy wyższej przed skutkami awarii w warstwie prokołu IP. Protokół IP (Internet Protokol) jest podstawowym protokołem warstwy internetu i odpowiada on za przesyłanie pakietów zwanych datagramami. Jest to protokół bezpołączeniowy, datagramy przesyłane są przez sieć bez kontroli poprawności ich dostarczenia. Wewnątrz datagramu IP umieszczane są segmenty TCP oraz pakiety UDP w celu dalszego ich przesłania.Protokół TCP w odniesieniu do IP posiada rozszerzone możliwości, do których zaliczyć można:
- strumienie – sformatowane dane są transportowane w postaci strumieni bitów zorganizaowancyh w bajty lub obiekty ośmio bitowe,
- buffer flow control – czyli kontrola zajętości bufora zapobiegająca przepełnianiom buforów powiązanych ze strumieniem danych. Wolniejszy proces ma zapenioną możliwość nadążania z odbieraniem oraz przetwarzaniem danych,
- detekcja i korekcja błędów transmisji – w przypadku wystąpienia błędu w transmisji następuje powiadomienie o tym fakcie obu stron, a następnie w celu zaradzeniu na wystąpienie błędu następuje powtórna transmisja brakujących pakietów,
- połączenie full-duplex – umożliwiające jednoczesną transmisję w obu kierunkach.
Protokół tworzący internet (TCP/IP) opisywany jest w dwojaki sposób:
- za pomocą siedmiowarstwowego modelu ISO/OSI,
- uproszczonego modelu czterowarstwowego.
Warstwy z modelu uproszczonego pokrywają się z odpowienimi funkcjami z modelu ISO/OSI. Najważniejszymi są warstwy: sieciowa oraz transportowa, drugoplanowymi
są natomiast warstwy: dostępu do sieci i aplikacji. Wspominając o warstwach nadmienić należy, iż najniższą warstwą w hierarchi architektury protokołu TCP/IP jest warstwa dostępu do sieci. Na jej poziomie dodaje się nagłówki oraz zakończenie do datagramów IP. W wyniku czego uzyskuje się tzw. „ramki”, które są następnie przesyłane w sieci.
Opis czterech warstw modelu TCP/IP:
- warstwa aplikacji – obsługuje protokoły wyższego poziomu, aspekty reprezentacji, kodowanie oraz kontrolę dialogu. TCP/IP łączy wszystkie aspekty zwiazane z plikacją w jednej warstwie oraz zapewnia prawidłowe pakowanie dla następnej warstwy. Warstwa aplikacji nazywana jest warstwą przetwarzania.
- warstwa transportu – zajmuje się apsektami zwiazanymi z niezawodnością, kontrolę przepływu i retransmisją. Protokół TCP dostarcza metody tworzenia niezawodnej komunikacji sieciowej cechujacej się dobrym przepływem informacji. TCP to protokół połączeniowy. Obsługuje dialog między źródłem a miejscem przeznaczenia, pakując jednocześnie informacje warstwy aplikacji w jednostki zwane segmentami. Warstwa ta nazywana jest czasami warstwą hots-do-hosta.
- warstwa internetowa (sieciowa) – jej zadaniem jest wysyłanie pakietów źródłowych z dowolnej sieci w sieci rozległej oraz dostarczanie ich do miejsca przeznaczenia niezależnie od ścieżek i sieci napotkanych po drodze. Protkołem zarządzającym tą wartswą jest protokół IP. W tej warstwie nastepuje wyznaczenie najlepszej ścieżki i komunikacji pakietów.
- warstwa dostępu do sieci – zajmuje się aspektami wymaganymi przez pakiet protokołu IP do przejścia fizycznym łączem z jednego urządzenia do drugiego, bezpośrednio połączonego.Obejmuje szczegóły związane z technologiami LAN i WAN, a także wszystkie zadania warstwy fizycznej i łącza danych w modelu OSI.
Warstwy modelu odniesienia TCP/IP opracowane zostały dla Ministerstwa Obrony Stanów Zjednoczonych i miały zawsze zapewniać możliwość przemieszczania się pakietów niezależnie od stanów konkretnych węzłów czy sieci rozległych. Stanowią one standard na którym wyrósł Internet.
W skład protokołu TCP/IP wchodzą:
a) protokoły transferu danych:
- IP (Internet Protocol),
- TCP (Transmission Control Protocol),
- UDP (User Datagram Protocol),
- ICMP (Internet Control Message Protocol),
- SNMP (Simple Network Management Protocol),
- TELNET (Network Terminal Protocol),
- FTP (File Transfer Protocol).
W skład połączenia uzyskanego za pomocą TCP zaliczyć można:
- wysłanie bitu SYNC/ACK od strony próbującej nawiązać połączenie,
- odpowiedź w postaci SYNC/ACK potweirdzające nawiązanie połączenia,
- zamknięcie połączenia za pomocą pakietu FIN.
Do największych zalet protokołów TCP/IP zaliczyć można:
- niezależność od specyfikacji sprzętowo-programowej systemów,
- możliwość integracji wielu różnych rodzajów sieci,
- wspólny schemat adresacji,
- istnienie standardowych protokołów warstw wyższych.
W skład najbardziej znanych protokołów warstwy aplikacji korzystających z protokołu TCP należą:
- Telnet (Network Terminal Protokol) pozwalający na rozpoczęcie sesji poprzez sieć dla usług terminalowych,
- FTP (File Transfer Protokol) umożliwiający przesyłanie plików,
- TFTP (Trivial File Transfer Protokol), który stanowi uproszczoną wersję protokołu FTP i wykorzystywany jest przy prostych usługach transferu plików,
- SMTP (Simple Mail Transfer Protokol) umożliwiający na wymianę poczty elektronicznej,
- HTTP (Hyper Text Transfer Protokol) udostępniający w sieci strony zapiasane na serwerach WWW (World Wide Web).
Delphi umożliwia zestawić prostą komunikację dwóch programów przez gniazdo w obszarze sieci poprzez zastosowanie komponentów IdTCPClient oraz IdTCPServer. Pierwszym krokiem zmierzającym do uzyskania w/w komunikacji jest ustalenie wspólnego portu zarówno dla aplikacji klient jak i serwer.
//aplikacja typu klient
IdTCPClient1.Port :=3500;
//aplikacja typu serwer
IdTCPServer1.DefaultPort := 3500;
Krok drugi - zdefiniowanie adresu IP serwera po stronie klienta:
{
Adres IP 127.0.0.1 jak opisano powyżej umożliwia uzyskanie testowego połączenia.
}
IdTCPClient1.Host := 127.0.0.1;
Krok trzeci - włączenie aplikacji typu serwer w tryb nasłuchiwania
IdTCPServer1.Active := true;
Tak przygotowana aplikacja klienta i serwera jest już przygotowana do nawiązania połączenia.
Krokiem kolejnym jest nawiązanie połączenia przez klienta z serwerem:
IdTCPClient1.Connect;
Za pomocą kolekcji Bindings można nawiązywać połączenia z wieloma adresami IP oraz portami.
Komponent IdTCPServer umożliwia w odpowiednim zdarzeniu obsłużyć przychodzące połączenie ze strony klienta, co możemy wykorzystać do utworzenia logu zdarzeń.
Procedure Tform1.IdTCPServer1Connect(Athread: TidPeerThread);
begin
Memo1.lines.add("Połączenie od: " + Athread.Connection.Socked.Binding.PeerIP);
end;
Kolejnym krokiem po ustanowieniu połączenia jest ustawienie komunikacji pomiędzy aplikacją typu klient i serwer. Zwykle komunikacja oparta jest na łańcuchach tekstowych. Gniazda, zarówno serwera jak i klienta, dysponują metodami odczytu i zapisu przeznaczonymi do przesyłania danych.
Po stronie klienta wysłanie ciągów znaków tekstowych odbywa się poprzez zastosowanie polecenia: IdTCPClient1.Write.
Rozbudowując zdarzenie OnClick przycisku Button uzyskujemy:
procedure TForm1.Button1Click(Sender: TObject);
begin
if Edit1.Text <> '' then
begin
//nawiązanie połączenia
if not IdTCPClient1.Connected then
begin
try
IdTCPClient1.Connect(-1);
except
on exception do
begin
Showmessage('Nie można nawiązać połaczenia z serwerem: '
+ IdTCPClient1.Host);
end;
end;
end;
//rozłączenie
if IdTCPClient1.Connected then
begin
//wysłanie wiadomości
IdTCPClient1.Write(Edit1.Text);
IdTCPClient1.Disconnect;
end;
end;
end;
Po stronie serwera należy rozbudować zdarzenie OnConnect:
procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
begin
Memo1.Lines.Add('Połączenie od: '
+ AThread.Connection.Socket.Binding.PeerIP);
Memo1.Lines.Add('Otrzymany tekst: '
+ Athread.Connection.AllData);
end;
Cały kod programu:
unit Main_Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdTCPServer, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient, StdCtrls;
type
TForm1=class(TForm)
Button1: TButton;
Edit1: TEdit;
Memo1: TMemo;
IdTCPClient1: TIdTCPClient;
IdTCPServer1: TIdTCPServer;
procedure IdTCPServer1Connect(AThread: TIdPeerThread);
procedure Button1Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
//wyczyszczenie komponentów Edit1 i Memo1
Edit1.Clear;
Memo1.Clear;
//ustawienie portów
IdTCPServer1.DefaultPort := 3500;
IdTCPClient1.Port := 3500;
//ustawienie adresu IP po stronie klienta
IdTCPClient1.Host := '127.0.0.1';
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
//aktywacja serwera
If not IdTCPServer1.Active then
begin
IdTCPServer1.Active := true;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if Edit1.Text <> '' then
begin
//nawiązanie połączenia
if not IdTCPClient1.Connected then
begin
try
IdTCPClient1.Connect(-1);
except
on exception do
begin
Showmessage('Nie można nawiązać połaczenia z serwerem: '
+ IdTCPClient1.Host);
end;
end;
end;
//rozłączenie
if IdTCPClient1.Connected then
begin
IdTCPClient1.Write(Edit1.Text);
IdTCPClient1.Disconnect;
end;
end;
end;
procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
begin
Memo1.Lines.Add('Połączenie od: '
+ AThread.Connection.Socket.Binding.PeerIP);
Memo1.Lines.Add('Otrzymany tekst: '
+ Athread.Connection.AllData);
end;
end.
Inne sposoby wymiany informacji pomiędzy IdTCPServer a IdTCPClient:
- poprzez zdefiniowanie właściwości po stronie serwera (ustawienie rozkazu tekstowego, kodu numerycznego, wyniku tekstowego):
- poprzez obsługę zdarzenia OnCommand:
//Serwer
Procedure Tform1.IdTCPServer1TidCommandHandler1Command (Asender: TIdCommand);
begin
Asender.Thread.Connection.Writeln("Odpowiedź serwera");
end;
//Klient
Procedure Tform1.ButtonClick(Sender: TObject);
begin
IdTCPClient1.WriteLn("execute");
Showmessage(IdTCPClient1.ReadLn);
end;
Prosty przykład odpowiedzi serwera: "Ping" ...
unit indy_ping_unit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
IdAntiFreezeBase, IdAntiFreeze, IdTCPServer;
type
TForm1 = class(TForm)
Memo1: TMemo;
Edit1: TEdit;
Label1: TLabel;
Button1: TButton;
IdTCPClient1: TIdTCPClient;
IdAntiFreeze1: TIdAntiFreeze;
Button2: TButton;
IdTCPServer1: TIdTCPServer;
procedure IdTCPServer1Execute(AThread: TIdPeerThread);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button2Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Text := '';
Memo1.Clear;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
If Edit1.Text <> '' then
begin
IdTCPClient1.Host := Edit1.Text;
IdTCPClient1.Port := 6000;
IdTCPClient1.ReadTimeout := 5;
end;
if (not IdTCPClient1.Connected) and (IdTCPClient1.Host <> '') then
begin
IdTCPClient1.Connect(-1);
end;
while IdTCPClient1.Connected do
begin
IdTCPClient1.WriteLn('PING');
Memo1.Lines.Add(IdTCPClient1.ReadLn('', 3000));
if IdTCPClient1.ReadLnTimedOut then
begin
MessageDlg('Timeout!', mtInformation, [mbOk], 0);
Exit;
end;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
IdTCPServer1.DefaultPort := 6000;
if not IdTCPServer1.Active then
begin
IdTCPServer1.Active := true;
Button2.Visible := false;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if IdTCPServer1.Active then
begin
IdTCPServer1.Active := false;
end;
end;
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
LLine: string;
begin
Sleep(1000);
LLine := AThread.Connection.ReadLn;
if LLine = 'PING' then
begin
AThread.Connection.WriteLn('250');
end;
end;
end.
UDP
User Datagram Protocol (UDP) działa w sposób bezpołączeniowy. Zapewnia więc tak samo zawodny sposób dostarczania pakietów co protokół IP. W protokole tym nie uwzględniono jakiejkolwiek kontroli transmisji czy korekcji błędów, konsekwencją czego pakiety UDP mogą zostać zagubione, zduplikowane albo też przybyć w nieprawidłowej kolejności. Dzięki
wykorzystaniu mniejszych nagłówków niż ma to miejsce w przypadku TCP pozwala na lepsze wykorzystanie przepustowości łączy i dzięki temu na szybsze przetwarzanie pakietów.
W skład najbardziej znanych protokołów warstwy aplikacji korzystających z protokołu UDP zaliczyć można:
- DNS (Domain Name Service) służący do zamiany adresów IP na nazwy,
- RIP (Routing Information Protokol) służący do wymiany informacji związanych z aktualizacją reguł doboru tras w węzłach sieci,
- NFS (Network File System) umożliwiający współdzielenie plików przez wiele komputerów połączonych w sieci.
W celu skorzystania z User Datagram Protocol w Delphi poprzez INDY należy zastosować IdUDPClient oraz IdUDPServer. Struktura programu jest podobna jak w przypadku pakietu TCP (komponentów IdTCPClient oraz IdTCPServer).
Kod źródłowy programu korzystającego z protokołu UDP poprzez INDY przedstawia poniższy przykład:
unit udp_Unit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdUDPServer, IdBaseComponent, IdComponent, IdUDPBase, IdUDPClient,
StdCtrls, IdSocketHandle, IdTCPServer;
type
TForm1=class(TForm)
IdUDPClient1: TIdUDPClient;
IdUDPServer1: TIdUDPServer;
Edit1: TEdit;
Button1: TButton;
Memo1: TMemo;
procedure IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
procedure IdUDPServer1Status(ASender: TObject; const AStatus: TIdStatus;
const AStatusText: string);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Clear;
Memo1.Clear;
IdUDPClient1.Port := 36000;
IdUDPServer1.DefaultPort := 36000;
IdUDPServer1.Active := true;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
IdUDPClient1.Host := '127.0.0.1';
IdUDPClient1.Send(Edit1.Text);
end;
procedure TForm1.IdUDPServer1Status(ASender: TObject; const AStatus: TIdStatus;
const AStatusText: string);
begin
Memo1.Lines.Add(AStatusText);
end;
procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
sText: string;
begin
//do uses dodać: IdSocketHandle
Memo1.Lines.Add(ABinding.PeerIP);
AData.Position := 0;
SetLength(sText, AData.Size);
AData.ReadBuffer(sText[1], AData.Size);
Memo1.Lines.Add(sText)
end;
end.
Procedurę odczytu można również zbudować korzystając ze strumieni:
procedure IdUDPServerUDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
Text: string;
StrStream: TStringStream;
begin
StrStream := TStringStream.Create('');
try
StrStream.CopyFrom(AData, AData.Size);
Text := StrStream.DataString;
finally
StrStream.Free;
end;
end;
Obsługa poczty - wysyłanie (SMTP) i odbieranie (POP3)
W celu używania protokołów pocztowych w Delphi za pomocą pakietu INDY niezbędne jest umieszczenie komponentu komunikatów (IdMessage) w naszej aplikacji. Wysyłanie poczty nastąpi po jego wypełnieniu i użyciu komponentu IdSMTP. Odbiór wiadomości pocztowej umożliwia komponent IdPOP3, który zwraca obiekt IdMessage.
SMTP
SMTP - Simple Mail Transfer Protocol. Protokół ten jest głównie używany do przenoszenia poczty elektronicznej. Standardowo serwery SMTP oczekują na przychodzącą pocztę na porcie 25. Odebraną pocztę kopiują do odpowiednich skrzynek pocztowych. Jeśli wiadomość nie może zostać dostarczona, nadawcy zostaje zwrócony komunikat błędu zawierający początkowy fragment wiadomości.Przykładowy kod źródłowy wysyłania wiadomości pocztowej:
procedure Tform1.wyslij();
begin
//czyszczenie zawartości komponentu IdMessage
IdMessage1.Clear;
//ustawienie adresu IP/nazwy serwera
IdSMTP1.Host :=Edit1.Text;
//ustawienie nazwy użytkownika
IdSMTP1.Username := Edit2.Text;
//ustawienie hasła użytkownika
IdSMTP1.Password := Edit3.Text;
//ustawienie trybu authentifikacji
IdSMTP1.AuthenticationType := atLogin;
//nawiązanie połączenia w przypadku jego braku
if not IdSMTP1.Connected then
begin
try
StatusBar1.SimpleText := 'Zestawianie połączenia z serwerem ...';
//nawiązywanie połączenia
IdSMTP1.Connect(-1);
StatusBar1.SimpleText := 'Połączony ...';
except
on exception do
begin
StatusBar1.SimpleText :='BŁĄD !!! Wysyłanie poczty !!! Polączenie z serwerem '
+ IdSMTP1.Host + ' niepowiodło się !!!';
end;
end;
end;
//jeżeli połaczenie jest zestawione - wysyłanie wiadomości
if IdSMTP1.Connected then
begin
//dodanie informacji od kogo
IdMessage1.From.Text := Edit4.Text;
//dodanie tematu
IdMessage1.Subject :=Edit5.Text;
//dodanie adresu odbiorcy
IdMessage1.Recipients.Add.Text :=Edit6.Text;
//dodanie załącznika do wiadomości
TidAttachment.create(IdMessage1.MessageParts, ExtractFilePath(ParamStr(0)) + 'zalacznik.txt');
StatusBar1.SimpleText := 'Wysyłanie wiadomości ...';
Try
//wysyłanie wiadomości
IdSMTP1.Send(IdMessage1);
StatusBar1.SimpleText := 'Wiadomość wysłana.';
//czyszczenie komponentu IdMessage
IdMessage1.Clear;
except
on exception do
begin
showmessage('Błąd przy wysyłaniu wiadomości !!!');
StatusBar1.SimpleText := 'Błąd przy wysyłaniu wiadomości !!!';
//czyszczenie komponentu IdMessage
IdMessage1.Clear;
end;
end;
end;
end;
POP3
POP3 - (Post Office Protocol) służy do przenoszenia poczty elektronicznej z serwera pocztowego na komputer użytkownika. Protokół oparty jest na architekturze klient-serwer, w której pocztę odbiera serwer pocztowy. Serwer przechowuje wiadomość aż do momentu, gdy użytkownik się zaloguje i ją pobierze.Przykładowy kod źródłowy odbioru wiadomości pocztowej:
procedure Tform1.obierz ();
var
il_wiad : integer; //ilość wiadomości
il_zal : integer; //ilość załączników
zal_nazwa : string; //nazwa załącznika
begin
//czyszczenie komponentu IdMessage
IdMessage1.Clear;
//ustawienie adresu IP/nazwy serwera
IdPOP31.Host := Edit1.Text;
//ustawienie nazwy użytkownika
IdPOP31.Username := Edit2.Text;
//ustawienie hasła użytkownika
IdPOP31.Password := Edit3.Text;
//nawiązanie połączenia w przypadku jego braku
If not IdPOP31.Connected then
begin
try
statusbar1.SimpleText := 'Odbieranie poczty - zestawianie połączenia!!!';
//zestawianie połączenia
IdPOP31.Connect(-1);
statusbar1.SimpleText := 'Odbieranie poczty - połączony!!!';
except
on exception do
begin
statusbar1.SimpleText := 'Odbieranie poczty - błąd połączenia!!!';
end;
end;
end;
//odebranie wiadomości w przypadku pomyślnego nawiązania połączenia
if IdPOP31.Connected then
begin
//sprawdzenie ilości wiadomości na serwerze
il_wiad := IdPOP31.CheckMessages;
statusbar1.SimpleText := il_wiad;
while il_wiad > 0 do
begin
//czyszczenie komponentu IdMessage
IdMessage1.Clear;
//odbiór wiadomości z serwera, wypełnienie komponentu IdMessage
IdPOP31.Retrieve(il_wiad, IdMessage1);
//sprawdzenie ilości załączników w wiadomości
il_zal := IdMessage1.MessageParts.Count - 1;
Showmessage('Odbieranie wiadomości: ' + inttostr(il_wiad) + ' Od: ' + IdMessage1.From.Text + ' Temat: ' + IdMessage1.Subject + " Załączników: " + inttostr(il_zal);
while il_zal > 0 do
begin
if (IdMessage1.MessageParts.Items[il_zal] is TIdAttachment) then
begin
zal_nazwa := TIdAttachment(IdMessage1.MessageParts.Items[il_zal]).Filename; TIdAttachment(IdMessage1.MessageParts.Items[il_zal]).SaveToFile(ExtractFilePath(ParamStr(0)) + zal_nazwa);
end;
il_zal := il_zal - 1;
end;
//kasowanie wiadomości na serwerze
IdPOP31.Delete(il_wiad);
il_wiad := il_wiad - 1;
end;
end;
end;
HTTP
Protokół HTTP (Hyper-Text Transfer Protokol) jest kolejnym (poza protokołami obsługi wiadomości) z najbardziej popularnych. Po stronie klienta następuje czytanie plików, serwery natomiast generują i udostępniają strony HTML. Strony internetowe generowane są w sposób statyczny, jak i dynamiczny (np.; w odpowiedzi na wykonywane czynności użytkownika). Na podstawie wpisanego w przeglądarce adresu następuje wyszukanie (lokalizacja) adresu IP serwera i dane przesyłane są do przeglądarki użytkownika.
W przypadku gdy protokół HTTP nie zapewnia wystarczającego poziomu bezpieczeństwa wykorzystuje się jego rozbudowaną wersję: HTTPS. Rozbudowana wersja HTTPS umożliwia szyfrowanie danych pomiędzy klientem a serwerem i nosi ono nazwę SSL (Secure Socket Layer).
Zaimplementowanie w kodzie źródłowym Delphi protokołu HTTP jest możliwe dzięki kontrolce TIdHTTP (zakładka Indy Clients).
Połączenie. Metoda Connect
Zachowując się intuicyjnie, możemy w łatwy sposób nawiązać połączenie z serwerem poprzez wpisanie w metodzie Connect komponentu TIdHTTP adresu serwera wraz z portem.
IdHTTP.connect("www.google.pl", 80);
Status
W celu sprawdzenia statusu połączenia stosujemy zdarzenie OnStatus. Pozwala ono wychwycić na jakim etapie działa komponent TIdHTTP. Parametr AStatus zwraca informacje o stanie połączenia w formie danych:
- hsResolving - szukanie hosta,
- hsConnecting - próba połączenia,
- hsConnected - połączony,
- hsDisconnecting - rozłączenie,
- hsDisconnected - rozłączony.
Procedure TForm1.IdHTTPStatus(ASender: TObject; AStatus: TIdStatus; AStatusText: string );
begin
Memo1.Lines.Add(AStatusText);
case AStatus of
hsResolving: Memo1.Lines.Add("Wyszukiwanie hosta");
hsConnecting: Memo1.Lines.Add("Łączenie z hostem");
hsConnecting: Memo1.Lines.Add("Połączenie zestawione.");
hsDisconnecting: Memo1.Lines.Add("Rozłączanie ");
hsDisconnected: Memo1.Lines.Add("Rozłączono !");
end;
end;
Parametr AStatusText wyświetla tekstowy opis statusu w wersji angielskiej.
Metoda Post
Istotą metody Post jest przekazywanie danych w nagłówku HTTP do przeglądarki. Dane są przekazywane w postaci: nazwa_pola=wartosc_pol&nazwapola2=wartosc_pola2. Poszczególne elementy oddzielone są os siebie znakiem &, natomiast nazwa pola oddzielona jest od wartości znakiem równości ("=").
Wykorzystanie metody Post komponentu TIdHTTP sprowadzone jest do podania dwóch parametrów typu TStringStream (strumienie). Pierwszy z parametrów zawiera dane przesyłane do skryptu (wartość wejściowa), drugi parametr zawiera dane zwrócone przez skrypt (wartość wyjściowa).
Używając metody Post musimy podać jeszcze adres strony, do której przekazany zostanie nagłówek oraz treść IdHTTP.
Sposób użycia metody Post:
IdHTTP.Post("http://adres.www/index.php", Stream_in, Stream_out);
Metoda Get
Podobnie jak w przypadku metody Post poszczególne pola oddzielone są od siebie znakiem &. Podstawową różnicą jest natomiast sposób ich przekazywania. Dane dołączana są do adresu strony i wygląda to następująco: "http://www.google.pl/search-pole1=wartosc1&pole2=wartosc2". Metodą Get sugeruje się przekazywanie niewielkiej ilości danych.
Pobieranie kodu HTML polega na użyciu metody Get komponentu TIdHTTP. W wyniku działania metody Get kod HTML zostanie zwrócony w postaci tekstu (String).
var
html_tekst : string;
begin
html_tekst := IdHTTP.Get("http://www.google.pl/");
end;
Zapis strony do pliku na dysku lokalnym
Zastosowanie metody Get w korelacji ze strumieniem (String; TStream) pozwoli na zapisanie strony do pliku.
var
ms: TMemoryStream;
begin
ms := TMemoryStream.Create;
try
Edit1.Text := 'http://4programmers.net/Delphi/Indy';
IdHTTP1.Get(Edit1.Text, ms);
ms.SaveToFile(ExtractFilePath(ParamStr(0)) + FormatDateTime('yyyy-mm-dd', date) + '_' + FormatDateTime('hh_nn_ss_zzz', Time) + '_test.html');
finally
ms.Free;
end;
end;
Funkcje formatowania daty (FormatDateTime) użyte zostały ze względu na możliwy do wystąpienia błąd w przypadku istnienia pliku "*test.html" na dysku. Oczywiście można użyć polecenia języka związane z kasowaniem plików.
Oczywiście tak zapisany plik można otworzyć za pośrednictwem przeglądarki internetowej używając polecenia ShellExecute:
var
ms: TMemoryStream;
plik_nazwa : string;
begin
ms := TMemoryStream.Create;
try
Edit1.Text := 'http://4programmers.net/Delphi/Indy';
IdHTTP1.Get(Edit1.Text, ms);
plik_nazwa := ExtractFilePath(ParamStr(0)) + FormatDateTime('yyyy-mm-dd', date) + '_' + FormatDateTime('hh_nn_ss_zzz', Time) + '_test.html';
ms.SaveToFile(plik_nazwa);
finally
ms.Free;
end;
//OTWARCIE ZAPISANEGO PLIKU !!!
if fileexists(plik_nazwa) then
begin
ShellExecute(Handle, 'open',Pchar(plik_nazwa), nil, nil, SW_SHOWNORMAL);
end;
end;
Niestandardowy serwer HTTP
Budowę niestandardowego serwera HTTP opartego na INDY należy zacząć umieszczając na formie komponent TIdHTTPServer z palety Indy Servers. Po umieszczeniu komponentu niezbędne jest obsłużenie aktywacji i dezaktywacji komponentu. W celach testowych dobrze jest również dodać pole edycyjne przeznaczone na numer portu.
Włączenie serwera:
IdHTTPServer1.Active := true;
Wyłączenie serwera:
IdHTTPServer1.Active :=false;
Ustawienie domyślnego portu na którym będzie pracował serwer (ustwienie portu należy przeprowadzać przed uruchomieniem serwera):
IdHTTPServer1.DefaultPort := 80;
Zmieniając domyślne ustawienia portu serwera możliwe jest używanie kilku serwerów w jednym czasie.
Po uruchomieniu serwera metodą Active należy obsłużyć zdarzenie OnCommandGet odpowiedzialne za zwrócenie strony wraz z informacjami dodatkowymi:
procedure TForm1.IdHTTPServer1CommandGet(AThread: TIdPeerThread;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
html_result : string;
begin
//procedura zwraca stronę www
//logowanie
RichEdit1.Lines.Add(ARequestInfo.Document);
html_result := '<h1> INDY DEMO SERWER </h1>'
+ '<hr><b>To jest przykładowa testowa strona.</b><hr>'
+ '<p>Request: ' + ARequestInfo.Document + '</p>'
+ '<p>Host: ' + ARequestInfo.Host + '</p>'
+ '<p>Params: ' + ARequestInfo.UnparsedParams + '</p>';
AResponseInfo.ContentText := html_result;
end;
A oto kod źródłowy najważniejszych procedur naszego niestandardowego serwera:
//WŁĄCZENIE SERWERA
procedure TForm1.Button1Click(Sender: TObject);
var
//do uses dodać: idSocketHandle
Binding : TIdSocketHandle;
begin
//włączenie serwera
if not IdHTTPServer1.Active then
begin
IdHTTPServer1.DefaultPort := 80;
IdHTTPServer1.Bindings.Clear;
Binding := IdHTTPServer1.Bindings.Add;
Binding.Port := StrToIntDef(inttostr(IdHTTPServer1.DefaultPort), 80);
Binding.IP := '127.0.0.1';
try
IdHTTPServer1.Active := true;
except
on e: exception do
begin
ShowMessage(format('Exception %s in Activate. Error is:"%s".', [e.ClassName, e.Message]));
end;
end;
end;
if IdHTTPServer1.Active then
begin
Showmessage('HTTP Serwer właczony!.' + #13 + 'Nasłuchiwanie na porcie: ' + inttostr(IdHTTPServer1.DefaultPort));
end;
end;
//WYŁĄCZENIE SERWERA
procedure TForm1.Button2Click(Sender: TObject);
begin
//wyłaczenie serwera
if IdHTTPServer1.Active then
begin
IdHTTPServer1.Active := false;
end;
if not IdHTTPServer1.Active then
begin
Showmessage('HTTP Serwer wyłączony!.');
end;
end;
//OBSŁUGA ZDARZENIA ONCOMMANDGET
procedure TForm1.IdHTTPServer1CommandGet(AThread: TIdPeerThread;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
html_result : string;
begin
//procedura zwraca stronę www
//logowanie - pokazanie w RichEdit nazwy wyświetlanej strony
RichEdit1.Lines.Add(ARequestInfo.Document);
//budowa i wyświetlenie HTML-u w przeglądarce internetowej
html_result := '<h1> INDY DEMO SERWER </h1>'
+ '<hr><b>To jest przykładowa testowa strona.</b><hr>'
+ '<p>Request: ' + ARequestInfo.Document + '</p>'
+ '<p>Host: ' + ARequestInfo.Host + '</p>'
+ '<p>Params: ' + ARequestInfo.UnparsedParams + '</p>';
AResponseInfo.ContentText := html_result;
end;
W wyniku podania w adresie przeglądarki <PRE>http://localhost/test-user=tete</PRE> zobaczymy efekt działania serwera (można również użyć polecenia z numerem portu: http://localhost:80/test-user=tete) jak na poniższym przykładzie:
INDY DEMO SERWER
To jest przykładowa testowa strona.
Request: /test Host: localhost Params: user=tete
Powyższy przykład pokazuje tworzenie statycznej strony www. Jednakże możliwe jest również tworzenie stron dynamicznych dzięki komponentom serii Producer znajdujących się na karcie Internet.
Komponenty serii Producer:
- PageProducer - umożliwia modyfikację pliku HTML, w którym umieszczone zostały specjalne znaczniki. W czasie działania programu PageProducer zamienia znaczniki na właściwy kod. Dzięki takiej metodzie istnieje łatwy sposób modyfikacji wybranych fragmentów kodu HTML. Specjalne znaczniki, o których mowa, przetwarzane są w zdarzeniu OnTag komponentu PageProducer. Podstawowym formatem znaczniku specjalnego jest <#nazwaznacznikaspecjalnego>.
- DataSetPageProducer - dzięki niemu możliwe jest automatyczne zastępowanie znaczników nazwami pól ze źródła bazy danych.
- DataSetTableProducer - umożliwia on wyświetlać w formie tabeli dane otrzymywane z zapytania lub zbioru danych.
- QueryTableProducer i SQLQueryTableProducer - przeznaczeniem jest budowanie zapytań z parametrami na podstawie wprowadzonych danych w formularzu.
Prosty serwer HTTP
Podobnie jak w przypadku niestandardowego serwera HTTP na formie umieszczamy komponent TIdHTTPServer z palety Indy Servers. Dodajemy do formy pola TEdit (na adres serwera, port serwera, katalog dokumentu głównego index.html), przycisk TButton (w celu właczenia/wyłączenia serwera) oraz TMemo (w celu uzyskania prostego logu).
Do słowa uses dodajemy ponadto: idSocketHandle, IdGlobal, IdThreadMgr, IdThreadMgrDefault, syncobjs, IdThreadMgrPool, ExtCtrls, IdIntercept, IdIOHandlerSocket.
W momencie tworzenia formy obsługujemy zdarzenie OnCreate:
procedure TForm1.FormCreate(Sender: TObject);
begin
memo1.Clear;
Edit_adres.Text := '127.0.0.1';
Edit_port.Text := '8080';
Edit_kat.Text := 'C:\';
if IdHTTPServer1.Active then
begin
Button1.Caption := 'Wyłącz serwer HTTP';
memo1.Lines.Add('Serwer HTTP włączony, nasłuchiwanie na porcie: ' + Edit_port.Text);
end;
if not IdHTTPServer1.Active then
begin
Button1.Caption := 'Włącz serwer HTTP';
memo1.Lines.Add('Serwer HTTP wyłączony!!!');
end;
end;
Właczenie i wyłaczenie serwera obsługujemy poprzez zdarzenie OnClick przycisku Button:
procedure TForm1.Button1Click(Sender: TObject);
var
//do słowa uses dodać: idSocketHandle
Binding : TIdSocketHandle;
i : integer;
begin
i := 0;
if not IdHTTPServer1.Active then
begin
IdHTTPServer1.Bindings.Clear;
Binding := IdHTTPServer1.Bindings.Add;
Binding.Port := StrToIntDef(edit_port.text, 80);
Binding.IP := Edit_adres.text;
end;
if not DirectoryExists(edit_kat.text) then
begin
ShowMessage(Format('Web root katalog (%s) nieznaleziony.',[edit_kat.text]));
end;
if (DirectoryExists(edit_kat.text)) and (not IdHTTPServer1.Active) and (i=0) then
begin
try
IdHTTPServer1.Active := true;
ShowMessage(format('Nasłuchiwanie za połączeniem HTTP na %s:%d.',[IdHTTPServer1.Bindings[0].IP, IdHTTPServer1.Bindings[0].Port]));
except
on e: exception do
begin
ShowMessage(format('Wyjątek %s przy aktywacji. Błąd:"%s".', [e.ClassName, e.Message]));
end;
end;
i := 1;
end;
if (DirectoryExists(edit_kat.text)) and (IdHTTPServer1.Active) and (i=0) then
begin
IdHTTPServer1.Active := false;
ShowMessage(format('Nasłuchiwanie za połączeniem HTTP na %s:%d zakończone.',[IdHTTPServer1.Bindings[0].IP, IdHTTPServer1.Bindings[0].Port]));
end;
if IdHTTPServer1.Active then
begin
Button1.Caption := 'Wyłącz serwer HTTP';
memo1.Lines.Add('Serwer HTTP włączony, nasłuchiwanie na porcie: ' + Edit_port.Text);
end;
if not IdHTTPServer1.Active then
begin
Button1.Caption := 'Włącz serwer HTTP';
memo1.Lines.Add('Serwer HTTP wyłączony!!!');
end;
end;
Najważniejszą procedurą wysyłająca stronę jest procedura obsługująca zdarzenie OnCommandGet komponentu IdHTTPServer:
procedure TForm1.IdHTTPServer1CommandGet(AThread: TIdPeerThread;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
LocalDoc: string;
ByteSent: Cardinal;
ResultFile: TFileStream;
begin
{
Wywołanie serwera: http://127.0.0.1:8080/
}
LocalDoc := ExpandFilename(edit_kat.text + 'index.html');
if FileExists(LocalDoc) then
begin
if AnsiSameText(Copy(LocalDoc, 1, Length(edit_kat.text)), edit_kat.Text) then
begin
if AnsiSameText(ARequestInfo.Command, 'HEAD') then
begin
ResultFile := TFileStream.create(LocalDoc, fmOpenRead or fmShareDenyWrite);
try
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentType := GetMIMEType(LocalDoc);
AResponseInfo.ContentLength := ResultFile.Size;
finally
ResultFile.Free;
end;
end else
begin
ByteSent := IdHTTPServer1.ServeFile(AThread, AResponseInfo, LocalDoc);
end;
end;
end;
end;
oraz funkcja:
function TForm1.GetMIMEType(sFile: TFileName): String;
begin
result := MIMEMap.GetFileMIMEType(sFile);
end;
Cały kod źródłowy serwera zamieszczony jest poniżej:
unit http_serwer_unit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPServer,
IdCustomHTTPServer, IdHTTPServer,
//dodane do uses
idSocketHandle, IdGlobal, IdThreadMgr, IdThreadMgrDefault,
syncobjs, IdThreadMgrPool, ExtCtrls, IdIntercept,
IdIOHandlerSocket;
// -------------
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Edit_adres: TEdit;
Edit_port: TEdit;
Edit_kat: TEdit;
Button1: TButton;
Memo1: TMemo;
Label4: TLabel;
IdHTTPServer1: TIdHTTPServer;
procedure IdHTTPServer1CommandGet(AThread: TIdPeerThread;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
function GetMIMEType(sFile: TFileName): String;
public
{ Public declarations }
MIMEMap: TIdMIMETable;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
memo1.Clear;
Edit_adres.Text := '127.0.0.1';
Edit_port.Text := '8080';
Edit_kat.Text := 'C:\';
if IdHTTPServer1.Active then
begin
Button1.Caption := 'Wyłącz serwer HTTP';
memo1.Lines.Add('Serwer HTTP włączony, nasłuchiwanie na porcie: ' + Edit_port.Text);
end;
if not IdHTTPServer1.Active then
begin
Button1.Caption := 'Włącz serwer HTTP';
memo1.Lines.Add('Serwer HTTP wyłączony!!!');
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
//do słowa uses dodać: idSocketHandle
Binding : TIdSocketHandle;
i : integer;
begin
i := 0;
if not IdHTTPServer1.Active then
begin
IdHTTPServer1.Bindings.Clear;
Binding := IdHTTPServer1.Bindings.Add;
Binding.Port := StrToIntDef(edit_port.text, 80);
Binding.IP := Edit_adres.text;
end;
if not DirectoryExists(edit_kat.text) then
begin
ShowMessage(Format('Web root katalog (%s) nieznaleziony.',[edit_kat.text]));
end;
if (DirectoryExists(edit_kat.text)) and (not IdHTTPServer1.Active) and (i=0) then
begin
try
IdHTTPServer1.Active := true;
ShowMessage(format('Nasłuchiwanie za połączeniem HTTP na %s:%d.',[IdHTTPServer1.Bindings[0].IP, IdHTTPServer1.Bindings[0].Port]));
except
on e: exception do
begin
ShowMessage(format('Wyjątek %s przy aktywacji. Błąd:"%s".', [e.ClassName, e.Message]));
end;
end;
i := 1;
end;
if (DirectoryExists(edit_kat.text)) and (IdHTTPServer1.Active) and (i=0) then
begin
IdHTTPServer1.Active := false;
ShowMessage(format('Nasłuchiwanie za połączeniem HTTP na %s:%d zakończone.',[IdHTTPServer1.Bindings[0].IP, IdHTTPServer1.Bindings[0].Port]));
end;
if IdHTTPServer1.Active then
begin
Button1.Caption := 'Wyłącz serwer HTTP';
memo1.Lines.Add('Serwer HTTP włączony, nasłuchiwanie na porcie: ' + Edit_port.Text);
end;
if not IdHTTPServer1.Active then
begin
Button1.Caption := 'Włącz serwer HTTP';
memo1.Lines.Add('Serwer HTTP wyłączony!!!');
end;
end;
procedure TForm1.IdHTTPServer1CommandGet(AThread: TIdPeerThread;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
LocalDoc: string;
ByteSent: Cardinal;
ResultFile: TFileStream;
begin
{
Wywołanie serwera: http://127.0.0.1:8080/
}
LocalDoc := ExpandFilename(edit_kat.text + 'index.html');
if FileExists(LocalDoc) then
begin
if AnsiSameText(Copy(LocalDoc, 1, Length(edit_kat.text)), edit_kat.Text) then
begin
if AnsiSameText(ARequestInfo.Command, 'HEAD') then
begin
ResultFile := TFileStream.create(LocalDoc, fmOpenRead or fmShareDenyWrite);
try
AResponseInfo.ResponseNo := 200;
AResponseInfo.ContentType := GetMIMEType(LocalDoc);
AResponseInfo.ContentLength := ResultFile.Size;
finally
ResultFile.Free;
end;
end else
begin
ByteSent := IdHTTPServer1.ServeFile(AThread, AResponseInfo, LocalDoc);
end;
end;
end;
end;
function TForm1.GetMIMEType(sFile: TFileName): String;
begin
result := MIMEMap.GetFileMIMEType(sFile);
end;
end.
FTP
FTP (File Transfer Protocol) - protokół ten działa na zasadzie klient-serwer. Zdefiniowany jest jako jedna z usług sieciowych w warstwowym modelu TCP/IP, który opisujące funkcje sieci komputerowych. Protokół ten określa sposób przesyłania plików pomiędzy dwoma komputerami. Połączenie z serwerem FTP następuje na zasadzie autoryzacji użytkownika, a dostęp do poszczególnych plików i katalogów uzależniony jest od posiadanych uprawnień logującego się użytkownika.W celu zbudowania aplikacji typu klient niezbędne jest umieszczenie na formie projektu komponentu IdFTP z panelu Indy Client. Przy budowie aplikacji typu serwer na formie należy umieścić komponent IdFTPServer z panelu Indy Servers.
Klient FTP
Pierwszą rzeczą jaką możemy zrobić (nie musimy) jest ustalenie portu na jakim ma pracować klient FTP (standardowo jest to port numer 21). Zmianę portu umożliwia nam metoda Port komponentu IdFTP:
IdFTP1.Port := '21';
Następnym przed nawiązaniem połączenia jest zdefiniowanie adresu serwera, nazwy użytkownika oraz jego hasła:
IdFTP1.Username := 'anonymous';
IdFTP1.Password := 'haslo';
IdFTP1.Host := '127.0.0.1';
Serwery FTP przeznaczone do użytku publicznego pozwalają przeważnie na uzyskanie anonimowego dostępu do określonych zasobów osobom, które posługują się identyfikatorem 'anonymous'.
Mając ustalone powyższe parametry możemy nawiązać połączenie metoda Connect.
if not IdFTP1.Connected then
begin
IdFTP1.Connect();
end;
W celu rozłączenia z serwerem FTP należy użyć metody Disconnect.
if IdFTP1.Connected then
begin
IdFTP1.Disconnect;
end;
Zbudowanie programu na powyższych zasadach tworzyć może jedynie zarys stosowanych metod w aplikacji typu klient. Każdy klient FTP umożliwia dokonywanie pewnych czynności zarówno po stronie serwera jak i na dysku lokalnym. Należy zatem obsłużyć między innymi metody wysyłania i odbierania plików/katalogów, tworzenia nowych katalogów na serwerze, zmiany trybu przesyłania danych (tekstowo/binarnie). Niezbędne jest również dodanie elementów wizualnych, których zadaniem będzie prezentacja danych w formie okienkowej.
Metoda Put obsługuje wysyłanie danych na serwer.
var
localfile, remotefile : string
begin
IdFTP1.Put(LocalFile, RemoteFile);
end;
Gdzie:
- localfile - pełna ścieżka wraz z nazwą pliku na dysku lokalnym,
- remotefile - nazwa pliku wysyłanego na serwer.
Metoda Get obsługuje pobieranie pliku z serwera.
var
localfile, remotefile : string
begin
IdFTP1.get(RemoteFile, LocalFile);
end;
Gdzie:
- remotefile - nazwa pliku pobieranego z serwera,
- localfile - pełna ścieżka wraz z nazwą pliku zapisywana na dysku lokalnym.
Tworzenie nowych katalogów na serwerze obsługuje metoda MakeDir
var
nowy_kat : string;
begin
IdFTP1.MakeDir(nowy_kat);
end;
Zmianę katalogu na serwerze obsługuje metoda ChangeDir.
var
kat_zdalny : string;
begin
IdFTP1.ChangeDir(kat_zdalny);
end;
Metodę zmiany katalogów na serwerze jak również na dysku lokalnym dobrze jest zaimplementować w obsłudze zdarzenia elementów wizualnych (takich jak np.: ListView).
Zmianę trybu przesyłania danych obsługuje metoda TransferType. W celu zautomatyzowania wyboru można dodać obsługę metody do elementu TRadioGroup. Do słowa uses należy dodać: IdFTPCommon.
case RadioGroup1.ItemIndex of
0: IdFTP1.TransferType := ftAscii;
1: IdFTP1.TransferType := ftBinary;
end;
Serwer FTP
W skład najważniejszych elementów serwera FTP wchodzić musi obsługa zdarzeń:
- OnAfterUserLogin - w obsłudze zdarzenia ustawia się parametry startowe,
- OnUserLogin - w obsłudze zdarzenia dokonujemy kontroli poprawności logującego się użytkownika,
- OnStoreFile - w obsłudze zdarzenia definiujemy zachowanie serwera w przypadku odbierania pliku od klienta,
- On RetrieveFile - w obsłudze zdarzenia definiujemy zachowanie serwera w przypadku żądania pobrania pliku przez klienta,
- OnChangeDirectory - w obsłudze zdarzenia definiujemy zachowanie serwera w przypadku otrzymania żądania zmiany katalogu przez klienta,
- OnListDirectory - w obsłudze zdarzenia definiujemy zachowanie serwera w przypadku otrzymania żądania ze strony klienta podania struktury plików i katalogów,
- OnMakeDirectory - jak nazwa wskazuje zdarzenie obsługuje żądanie utworzenia katalogu na serwerze.
Zdarzenie OnAfterLogin:
procedure TForm1.IdFTPServer1AfterUserLogin(ASender: TIdFTPServerThread);
begin
//ustawiamy katalog domowy podczas logowania
ASender.HomeDir := '\';
ASender.CurrentDir := '\';
end;
Zdarzenie OnUserLogin:
procedure TForm1.IdFTPServer1UserLogin(ASender: TIdFTPServerThread;
const AUsername, APassword: string; var AAuthenticated: Boolean);
begin
//sprawdzenie użytkownika
AAuthenticated := ((AUsername = 'anonymous') and (APassword = 'haslo'));
if AAuthenticated = true then
begin
//funkcje po rozpoznaniu użytkownika
end;
end;
Zdarzenie OnStoreFile:
procedure TForm1.IdFTPServer1StoreFile(ASender: TIdFTPServerThread;
const AFileName: string; AAppend: Boolean; var VStream: TStream);
var
appdir : string;
begin
appdir := sc_programu:=ExtractFilePath(ParamStr(0));
//zmienną appdir można zdefiniować jako public
//oraz w obsłudze zdarzenia OnAfterLogin podstawić wartość jak powyżej
//odbieranie pliku
if not Aappend then
begin
//odbieranie pliku - nowy plik
VStream := TFileStream.Create(AppDir + AFilename,fmCreate);
end;
if Aappend then
begin
//odbieranie pliku - nadpisywanie istniejącego
VStream := TFileStream.Create(AppDir + AFilename,fmOpenWrite);
end;
end;
Zdarzenie On RetrieveFile:
procedure TForm1.IdFTPServer1RetrieveFile(ASender: TIdFTPServerThread;
const AFileName: string; var VStream: TStream);
var
appdir : string;
begin
appdir := sc_programu:=ExtractFilePath(ParamStr(0));
//zmienną appdir można zdefiniować jako public
//oraz w obsłudze zdarzenia OnAfterLogin podstawić wartość jak powyżej
//wysyłanie pliku
VStream := TFileStream.Create(AppDir + AFilename,fmOpenRead);
Application.ProcessMessages;
end;
Zdarzenie OnChangeDirectory:
procedure TForm1.IdFTPServer1ChangeDirectory(ASender: TIdFTPServerThread;
var VDirectory: string);
begin
//zmiana katalogu
Asender.CurrentDir := VDirectory;
end;
Zdarzenie OnListDirectory (zmienne appdir i change_dir typu string do zdefiniowania jako public w innych częściach kodu źródłowego programu):
procedure TForm1.IdFTPServer1ListDirectory(ASender: TIdFTPServerThread;
const APath: string; ADirectoryListing: TIdFTPListItems);
var
LFTPItem :TIdFTPListItem;
SR : TSearchRec;
SRI : Integer;
begin
//przesłanie zawartości katalogu do klienta
SRI := FindFirst(AppDir + change_dir + '*.*', faAnyFile - faHidden - faSysFile, SR);
While SRI = 0 do
begin
LFTPItem := ADirectoryListing.Add;
LFTPItem.FileName := SR.Name;
LFTPItem.Size := SR.Size;
LFTPItem.ModifiedDate := FileDateToDateTime(SR.Time);
Application.ProcessMessages;
if SR.Attr = faDirectory then
LFTPItem.ItemType := ditDirectory
else
LFTPItem.ItemType := ditFile;
SRI := FindNext(SR);
end;
FindClose(SR);
SetCurrentDir(AppDir + '..');
end;
Zdarzenie OnMakeDirectory:
procedure TForm1.IdFTPServer1MakeDirectory(ASender: TIdFTPServerThread;
var VDirectory: string);
begin
//tworzenie katalogu
if not ForceDirectories(Appdir + VDirectory) then
begin
//można dodać komunikat błędu na serwerze
Memo1.Lines.Add('Błąd: ' + Appdir + VDirectory);
end;
end;
IdThreadComponent
Jednym z prostrzych sposobów zbudowania aplikacji nieblokującej działania podczas wykonywania poleceń INDY jest wykorzystanie komponentu IdThreadComponent. Dzięki niemu uzyskamy efekt wątkowości. Ogólny sposób użycia prezentuje poniższy schemat:
procedure TForm1.btnConnect1Click(Sender: TObject);
begin
//uruchomienie wątku
IdThreadComponent1.Start;
end;
procedure TForm1.IdThreadComponent1Run(Sender: TIdThreadComponent);
begin
//wykonywany kod w wątku
{
- np.: funkcje pobierania, wysyłania pliku IdFTP1.Get czy IdFTP1Put(),
}
//zatrzymanie wątku po wykonaniu kodu
IdThreadComponent1.Stop;
end;
Użycie w powiązaniu z pakietem TCP
procedure T Form1.Button1Click(Sender: TObject);
begin
//wątek dla wysyłania wiadomości ...
IdThreadComponent1.Start;
end;
procedure TForm1.IdThreadComponent1Run(Sender: TIdCustomThreadComponent);
begin
IdTCPClient1.Host :=label1.Caption;
if (richedit1.Lines.Text <> '') and (label1.Caption <> '') then
begin
if not IdTCPClient1.Connected then
begin
try
IdTCPClient1.Connect(60);
if IdTCPClient1.Connected then
begin
IdTCPClient1.Write(richedit1.Lines.Text);
IdTCPClient1.Disconnect;
end;
except
on exception do
begin
Memo1.Lines.Add('Wysłanie wiadomości do: '
+ label1.Caption + ' nie jest możliwe !!!');
end;
end;
end;
//zatrzymanie wątku
IdThreadComponent1.Stop;
end;
IdIcmpClient (Internet Control Message Protocol)
ICMP (Internet Control Message Protokol) jest drugim protokołem (podstawowym jest IP) warstwy Internetu i jest on ścicśle związany z protkołwem IP.Jego zadaniem jest przesyłanie komunikatów o nieprawidłowościach w pracy sieci. Pozwala on przesyłać wiadomości sterujące, które dotyczyć mogą: przepływu, testowania połączeń, wskazywania alternatywnych połączeń oraz wykrywania niedostępnych użytkowników.Zastosowanie komponentu IdIcmpClient umożliwia pozyskać informacje zwiazane z funkcjonowaniem urządzeń w sieci np.: routerów, stacji roboczych. Przesłanie polecenia ping i odebranie informacji umożliwia dokonać w/w kontroli. Za pomocą kontrolki IdIcmpClient pozyskać można również dodatkowe informacje związane z ilością przesyłanych bajtów, czasem życia, czasem oczekiwania na odpowiedź. Sposób użycia komponentu jest stosunkowo prosty. W aplikacji pisanej w Delphi należy umieścić na formie pole Edit (posłuży do wprowadzania adresu IP), przycisku Button (uruchomi wysyłanie pinga), komponentu Memo (zapisywane będą do komponentu informacje zwrotne). Ostatnim komponentem jaki umieszczamy na formie jest IdIcmpClient.
W obsłudze zdarzenia OnCreate formy dodajemy:
procedure TForm1.FormCreate(Sender: TObject);
begin
//wyczyszczenie pola Edit
Edit1.Text := '';
//wyczyszczenie komponentu Memo
Memo1.Clear;
end;
W obsłudze zdarzenia OnClick przycisku Button dodajemy:
procedure TForm1.Button1Click(Sender: TObject);
var
i : integer;
begin
//ustawiamy czas oczekiwania
IdIcmpClient1.ReceiveTimeout := 1000;
//wyłączamy dostępność przycisku button
button1.Enabled := False;
try
//ustawiamy adres IP
IdIcmpClient1.Host := Edit1.Text;
//wykonujemy pętlę 20 razy
for i := 1 to 20 do begin
//wysyłamy polecenie Ping
IdIcmpClient1.Ping;
//pozwalamy odetchnąć systemowi - obsłużyć komunikaty Windows
Application.ProcessMessages;
//dodatkowo można wykonać opóźnienie - w tym przypadku 1 sekundy
sleep(1000);
end;
finally
//finalizując włączamy dostępność przycisku button
button1.Enabled := True;
end;
end;
W obsłudze zdarzenia OnReply komponentu IdIcmpClient dodajemy:
procedure TForm1.IdIcmpClient1Reply(ASender: TComponent;
const AReplyStatus: TReplyStatus);
var
sTime: string; //nowa zmienna typu string
begin
//sprawdzanie błedów odpowiedzi ping'a (AReplyStatus.MsgType)
if (AReplyStatus.MsRoundTripTime = 0) then
sTime := '<1' //ustawienie wartości zmiennej dla wartości mniejszych niż 1
else
sTime := '='; //ustawienie wartości zmiennej
//wypełnienie komponentu Memo odpowiednio: ilością przesłanych bajtów,
//kolejnym numerem ID, czasem życia, zmienną sTime, czasem oczekiwania na odpowiedź
Memo1.Lines.Add(Format('%d bytes from %s: Sequence ID=%d TTL=%d Time%s%d ms',
[AReplyStatus.BytesReceived,
AReplyStatus.FromIpAddress,
AReplyStatus.SequenceId,
AReplyStatus.TimeToLive,
sTime,
AReplyStatus.MsRoundTripTime]));
end;
Przykład sprawdzający dostępność adresów w całym segmencie
unit ping_unit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdRawBase, IdRawClient, IdIcmpClient, IdBaseComponent, IdComponent,
IdIPWatch, StdCtrls, ComCtrls, Menus;
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Label1: TLabel;
RichEdit1: TRichEdit;
IdIPWatch1: TIdIPWatch;
IdIcmpClient1: TIdIcmpClient;
lbl_local_ip: TLabel;
lbl_numer_ip: TLabel;
Edit2: TEdit;
Edit3: TEdit;
Button2: TButton;
Edit4: TEdit;
PopupMenu1: TPopupMenu;
zapiszlog1: TMenuItem;
procedure zapiszlog1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure IdIcmpClient1Reply(ASender: TComponent;
const AReplyStatus: TReplyStatus);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
sc_programu : string;
host, segment1, segment2, segment3, segment4 : string;
operacja : integer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
//pobranie ścieżki dostępu do pliku exe naszej aplikacji
sc_programu:=ExtractFilePath(ParamStr(0));
//wyłaczenie historii komponentu IdIPWatch
IdIPWatch1.HistoryEnabled := false;
//ustawienie ścieżki dostępu do pliku z historią wraz z jego nazwą
IdIPWatch1.HistoryFilename := sc_programu + 'iphist.dat';
//pobranie adresu IP stacji roboczej
lbl_local_ip.Caption := IdIPWatch1.LocalIP;
lbl_numer_ip.Caption := '';
Edit1.Text := IdIPWatch1.LocalIP;
Edit2.Text := '1';
Edit3.Text := '254';
Edit4.Text := '2';
//zwolnienie komponentu IdIPWatch
IdIPWatch1.Free;
RichEdit1.Clear;
RichEdit1.PlainText := true;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i, j : integer;
begin
if Edit1.Text <> '' then
begin
host := Edit1.Text;
operacja := 1;
segment1 := copy(host, 1, (Pos('.', host)) - 1);
delete(host, 1, (Pos('.', host)));
segment2 := copy(host, 1, (Pos('.', host)) - 1);
delete(host, 1, (Pos('.', host)));
segment3 := copy(host, 1, (Pos('.', host)) - 1);
delete(host, 1, (Pos('.', host)));
segment4 := host;
Showmessage('Segment: ' + segment1 + '-' + segment2 + '-' + segment3);
RichEdit1.Lines.Add('Start ...');
Button1.Enabled := false;
IdIcmpClient1.ReceiveTimeout := 1000;
for j:=strtoint(Edit2.Text) to strtoint(Edit3.Text) do
begin
if operacja = 0 then
begin
break;
end;
for i:= 1 to strtoint(edit4.Text) do
begin
if operacja = 0 then
begin
break;
end;
IdIcmpClient1.Host := segment1 + '.' + segment2 + '.' + segment3 + '.' + inttostr(j);
lbl_numer_ip.Caption := IdIcmpClient1.Host;
Application.ProcessMessages;
try
IdIcmpClient1.Ping;
Except
//
end;
Application.ProcessMessages;
sleep(100);
end;
end;
Button1.Enabled := true;
RichEdit1.Lines.Add('... stop !');
end;
end;
procedure TForm1.IdIcmpClient1Reply(ASender: TComponent;
const AReplyStatus: TReplyStatus);
var
sTime : string;
begin
if (AReplyStatus.MsRoundTripTime = 0) then
sTime := '<1' //ustawienie wartości zmiennej dla wartości mniejszych niż 1
else
sTime := '='; //ustawienie wartości zmiennej
if (AReplyStatus.MsRoundTripTime >= 1000) then
begin
RichEdit1.Lines.Add(IdIcmpClient1.Host + ' - time out (' + inttostr(AReplyStatus.MsRoundTripTime) + ')');
end;
if (AReplyStatus.MsRoundTripTime < 1000) then
begin
RichEdit1.Lines.Add(Format('%d bytes from %s: Sequence ID=%d TTL=%d Time%s%d ms',
[AReplyStatus.BytesReceived,
AReplyStatus.FromIpAddress,
AReplyStatus.SequenceId,
AReplyStatus.TimeToLive,
sTime,
AReplyStatus.MsRoundTripTime]));
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
operacja := 0;
end;
procedure TForm1.zapiszlog1Click(Sender: TObject);
begin
RichEdit1.Lines.SaveToFile(sc_programu + segment1 + '-' + segment2 + '-' + segment3 + '.txt');
end;
end.
IdIPWatch
Komponent IdIPWatch pozwala w prosty sposób pobrać adres IP zestawu na którym uruchamiamy naszą aplikację. Po umieszczeniu na formie komponentu IdIPWatch należy obsłużyć np.: zdarzenie OnCreate formy dodając w niej funkcje obsługi komponentu IdIPWatch jak przedstawia poniższy przykład:
var
sc_programu : string; //nowa zmienna typu string
local_ip : string; //nowa zmienna typu string
begin
//pobranie ścieżki dostępu do pliku exe naszej aplikacji
sc_programu:=ExtractFilePath(ParamStr(0));
//wyłaczenie historii komponentu IdIPWatch
IdIPWatch1.HistoryEnabled := false;
//ustawienie ścieżki dostępu do pliku z historią wraz z jego nazwą
IdIPWatch1.HistoryFilename := sc_programu + 'iphist.dat';
//pobranie adresu IP stacji roboczej
local_ip := IdIPWatch1.LocalIP;
//zwolnienie komponentu IdIPWatch
IdIPWatch1.Free;
end;
IdConnectionIntercept
W/w komponent pozwala nam uzyskać wiecej informacji na temat zestawionego połączenia a zwłaszcza podczas transmisji (pakiety przychodzące oraz wychodzące). Na poniższym przykładzie widzimy prostą metodę jego zastosowania:
Przychodzące:
procedure Tklient_ftp_form.IdConnectionIntercept1Receive(
ASender: TIdConnectionIntercept; AStream: TStream);
var
Text: string;
StrStream: TStringStream;
begin
StrStream := TStringStream.Create('');
try
StrStream.CopyFrom(AStream, AStream.Size);
Text := Trim(StrStream.DataString);
log_intercept := Text;
RichEdit1.Lines.Add('<<- ' + Text);
finally
StrStream.Free;
end;
end;
Wychodzące:
procedure Tklient_ftp_form.IdConnectionIntercept1Send(
ASender: TIdConnectionIntercept; AStream: TStream);
var
Text: string;
StrStream: TStringStream;
begin
StrStream := TStringStream.Create('');
try
StrStream.CopyFrom(AStream, AStream.Size);
Text := Trim(StrStream.DataString);
if pos('PASS', Text) > 0 then
begin
RichEdit1.Lines.Add('->> Password ...');
end;
if pos('PASS', Text) = 0 then
begin
RichEdit1.Lines.Add('->> ' + Text);
end;
finally
StrStream.Free;
end;
end;
Zobacz też:
Kompendium, aplikacje sieciowe
Witam,
Mam pytanie odnośnie przykładu indy pop3. Jak ustawić polskie znaki w załącznikach w zmiennej: zal_nazwa
Gdy pobieram nazwa załącznika z polskimi znakami to krzaki. UTF8toANSI(zal_nazwa) --nie działa.
Prosiłbym gorąco o odpowiedź.
Dziekuję.
gdyby nie miliard bledow to by było wypas :D
ogolnie to nie ma czegoś takiego jak np.
IdHTTP.connect('www.google.pl', 80);
przynajmniej nie w indy 9.
najpierw sie okresla hosta, a potem tylko idhttp.connect;
Kocham przykłady.
Artykuł 9/10 XD
Znalazłem link do indy open source: http://www.indyproject.org/index.en.aspx
i dalej dla vcl: http://www.indyproject.org/Sockets/wizard/DownloadWizard.EN.aspx
Bardzo prosze o wsparcie niech ktos mi wysle indy automatyczny instalator dla delphi 7 na adres email eoodeo@gmail.com
niestety download producenta niedziala i musze wam zawrocic glowe
pozdrawiam
w jaki sposób można pobrać z serwera pop3 ilość wiadomości e-mail nowych jeszcze nieprzeczytanych?
z góry dziękuję za pomoc
INDY 10 - przykład z TBytes w odniesieniu do IdConnectionIntercept oraz IdFTP
na forme dodać: IdIOHandlerStack1 i IdConnectionIntercept1
należy ustawić w events
uzupełnić events IdConnectionIntercept1.receive i IdConnectionIntercept1.Send
IdIOHandlerStack1 w events powinno się samo uzupełnić:
IdIOHandlerStack1.Intercept.OnReceive := IdConnectionIntercept1Receive
IdIOHandlerStack1.Intercept.OnSend := IdConnectionIntercept1Send
procedure TForm1.IdConnectionIntercept1Receive(ASender: TIdConnectionIntercept;
var ABuffer: TBytes);
var
RecText: string;
i: Integer;
begin
RecText := '';
for i:= 0 to length(ABuffer)-1 do
begin
RecText := RecText + chr(ABuffer[i]);
end;
RichEdit_ftp.Lines.Add('->> ' + RecText);
end;
procedure TForm1.IdConnectionIntercept1Send(ASender: TIdConnectionIntercept;
var ABuffer: TBytes);
var
RecText: string;
i: Integer;
begin
RecText := '';
for i:= 0 to length(ABuffer)-1 do
begin
RecText := RecText + chr(ABuffer[i]);
end;
RichEdit_ftp.Lines.Add('<<- ' + RecText);
end;
i := -1;
sText := '';
repeat
i := i +1;
sText := sText + Char(Adata[i]);
until Char(adata[i]) = ''; //tu są dwa ' a nie jeden "
Memo1.Lines.Add(sText);
ODKODOWYWANIE TEKSTU W INDY 10
1 kendas to nie jest złe generowanie prodrocedure tylko w INDY10 TStream zamienili na TBytes i TBytes trzeba zamienic na String... Tylko jak to zrobbic. Skoro jedna literka to ileś tam bajtów to trzeba je pokoleji odczytywać tylko jak zapisać koniec?? 00000000??
zrobilem sciagnalem RAD STudio
Ojoj, ojoj... Co z tego, że były małe błędy?! Ja mam D6.0 i się można był domyśleć, że nie ma np: Username, tylko UserId itp... Patrzcie, co podpowiada w trakcie pisania sam HELP, a przestańcie biadolić, że coś Wam nie działa! Artykuł jest GIT i tu lepiej niech pozostanie;-) Zawsze można zerknąć i już WIEM-Y...
Jak wysłać za pomocą TCP CLIENT BUFOR JAK WYSLAC ZA POMOCA TCP SERVER BUFOR?
Mam Turbo delphi i prz instalacji wybrałem Indy 9 (bo wszyscy mówią że lepsze). I w kontrolkach mam:
TTcpServer (bez ID), TTcpClient (bez ID) TUDPSocket (to już całkiem inne) i nie umiem nawiązać połączenia. A chciałbym miedzy dwama kompami w necie, a nie w LANIE, acha i te kontrolki są w zakłatce Internet.
Przydałby sie jeszcze jakiś artukuł o IndySoap
Mam pytanko jakie mam zastosować komponenty aby zrobić komunikator internetowy( globalny) a nie tylko w sieci lokalnej??
Małe pytanie, jak zrobić żeby klient odczytywał wiadomość w TCP? bo w przykładzie podałeś tylko odczytywanie przez server...
<edit>Już odkryłem sam :P dzięki super artykuł!
Ze stronki http://www.indyproject.org/Sockets/Download/Files/Indy10.en.aspx wnioskuję, że jest wersja 10 która ma automatyczną instalkę:
<font color="navy">Indy 10 ...</span>
Installation
<font color="red">Automatic Install</span> - The Indy Plus Install is an automated installation kit provided by Atozed Software.
Source Code - Version 10.0.52
Development Snapshot - Instructions to obtain live source and compile manually.
Po wybraniu Automatic Install przejdziemy na stronkę Atozed i tam znajdziemy stronkę: http://www.atozed.com/indy/plus/Files.en.aspx skąd można pobrać instalki.
Nie umiem zainstalować tego Indy!!! Pomocy!!! Dużo różnych plików, Borland Delphi 2005 pisze, że to nie jest komponent real time design czy coś takiego i zgłasza brak jakichś plików. Czyżby to nie było kompatybilne z Delphi 2005? Błagam niech mi ktoś pomoże i nie śmiejcie się ze mnie, mam cztery katalogi: Core, Protocols, SuperCore i System. Co z tym zrobić?
Ok, niech tak zostanie, w końcu to nie ja tutaj zarządzam :P W końcu w dziale Delphi/Artykuły też jest link do tego tekstu. ok...
Przeniosłem ze względu na google. Jak wprowadzisz do wyszukiwania na google
słowo INDY i zaznaczysz szukaj na stronach kategorii: Polski to jako pierwszy dostajesz link do tego artykułu. Nie wiem czy zauważyłeś ale jest on często przeglądany (od grudnia 2005: 6860 wyświetleń co daje średnio około 850 odwiedzin na miesiąc). Może jednak zostawić artykuł w dziale Delphi ?
rk7771: czemu przeniosłeś spowrotem do Delphi/Indy? Zauważ, że dział główny Delphi zawiera opis języka a to mi wygląda na porządny artykuł. Po za tym strasznie ciężko trafić na ten tekst w dziale Delphi, gdyż jest tam pełno artykułów zaczynających się na "I" - uwierz mi.
// edit: widzę, że ustawiłeś przekierowanie w tekście Delphi/Artykuły/INDY do Delphi/INDY, a ja nadal jestem za tym, aby ten artykuł znajdował się w Delphi/Artykuły/INDY i tylko tam, w końcu nie tyczy się on opisu języka Delphi. Ale rób jak chcesz...
Shreq napisał: Kasowanie wiadomosci na serwerze przy uzyciu tego komponentu odbywa sie Z CHWILA WYWOLANIA metody Disconnect.
Ciakawa sugestia. Sprawdzałem na serwerze Suse (postfix) ...
Do listy bledow dorzuce jeszcze jeden. Autor napisal: "Serwer przechowuje wiadomość aż do momentu, gdy użytkownik się zaloguje i ją pobierze." Byc moze jest to prawda, ale nie w przypadku IdPOP3. Kasowanie wiadomosci na serwerze przy uzyciu tego komponentu odbywa sie Z CHWILA WYWOLANIA metody Disconnect. W podanym przykladzie jak i w poprawce do niego autorstwa jakuba tej metody brak - wiec wiadomosci spokojnie na serwerze zostaja... Sprawdzcie, jak nie wierzycie :)
No i zarowno konstrukcja
il_wiad := ((il_wiad) - 1); (jakubkrol)
jak i
il_wiad := il_wiad - 1; (autor)
wydaje mi sie nieco... ekhm.. egzotyczna... Czyzby nie wystarczylo
Dec( Il_wiad );
No ale takich "stylistycznych" kwiatkow jest w tym kodzie wiecej :)
Wydaje mi się, że warunek powinien brzmieć:
while il_zal >= 0 do
w przeciwnym razie omijany jest 0 element listy IdMessage1.MessageParts.
Delphi wie co to TIdAttachment jeśli korzystasz z INDY 9, a nie 10.
Dlaczego DELPHI 7 nie wie co to TIdAttachment?! :(
Dodałem - w częsci poświęconej TCP: "Prosty przykład odpowiedzi serwera: Ping ..."
Wysyłanie klient - serwer, OK. A odwrotnie?
Faktycznie, nie działa, może strona jest serwisowana. Spróbuj później ...
Znalazłem natomiast stronkę: http://www.atozed.com/indy/Demos/index.en.iwp jednakże odwołuje się ona do strony: http://www.indyproject.org/download/ która również nieodpowiada ...
Link do komponentow nie dziala!!!!!!!
ludzie wy już nie umiecie nazywać obiektów? Jak widać "Form1" to czuć lamerstwem
MASA BŁĘDÓW. NP.: W POP3:
NIE:
var
il_wiad : integer; //ilość wiadomości
il_zal : integer; //ilość załączników
zal_nazwa : string; //nazwa załącznika
begin
//czyszczenie komponentu IdMessage
IdMessage1.Clear;
//ustawienie adresu IP/nazwy serwera
IdPOP31.Host := Edit1.Text;
//ustawienie nazwy użytkownika
IdPOP31.Username := Edit2.Text;
//ustawienie hasła użytkownika
IdPOP31.Password := Edit3.Text;
//nawiązanie połączenia w przypadku jego braku
If not IdPOP31.Connected then
begin
try
statusbar1.SimpleText := 'Odbieranie poczty - zestawianie połączenia!!!';
//zestawianie połączenia
IdPOP31.Connect(-1);
statusbar1.SimpleText := 'Odbieranie poczty - połączony!!!';
except
on exception do
begin
statusbar1.SimpleText := 'Odbieranie poczty - błąd połączenia!!!';
end;
end;
end;
//odebranie wiadomości w przypadku pomyślnego nawiązania połączenia
if IdPOP31.Connected then
begin
//sprawdzenie ilości wiadomości na serwerze
il_wiad := IdPOP31.CheckMessages;
statusbar1.SimpleText := il_wiad;
end;
end;
TYLKO:
var
il_wiad : integer; //ilość wiadomości
il_zal : integer; //ilość załączników
zal_nazwa : string; //nazwa załącznika
begin
//czyszczenie komponentu IdMessage
IdMessage1.Clear;
//ustawienie adresu IP/nazwy serwera
IdPOP31.Host := Edit1.Text;
//ustawienie nazwy użytkownika
IdPOP31.Username := Edit2.Text;
//ustawienie hasła użytkownika
IdPOP31.Password := Edit3.Text;
//nawiązanie połączenia w przypadku jego braku
If not IdPOP31.Connected then
begin
try
statusbar1.SimpleText := 'Odbieranie poczty - zestawianie połączenia!!!';
//zestawianie połączenia
IdPOP31.Connect;
statusbar1.SimpleText := 'Odbieranie poczty - połączony!!!';
except
on exception do
begin
statusbar1.SimpleText := 'Odbieranie poczty - błąd połączenia!!!';
end;
end;
end;
//odebranie wiadomości w przypadku pomyślnego nawiązania połączenia
if IdPOP31.Connected then
begin
//sprawdzenie ilości wiadomości na serwerze
il_wiad := IdPOP31.CheckMessages;
statusbar1.SimpleText := 'Ilosc wiadomosci: '+IntToStr(il_wiad);
end;
end;
end;
Czy ktoś może zna zamiennik komponentu TextBrowser występującego w Kylik'sie dla wersji Delphi pod Windows? Można by dodać przykład przeglądarki internetowej opartej na komponentach INDY.
Coldpeer - nigdzie nie napisałem, że miałoby być w C++
raczej w jakimś globalnym dziale - po prostu opis pakietu Indy
Marooned: a dlaczego miałby być w C++,a nie w Delphi? :>
Ja nie miałem żadnego problemu, a korzystam z c++
Dlaczego ten art jest w Delphi ????
Przecież w BCB również działa Indy :|
Choć w sumie przykłady są w Delphi... ale tak jakoś nie teges...
Artykuł też mi się podoba. Zauważyłem jednak że w Indy10 jest mały bubel. Delphi (u mnie 2005) źle generuje procedurę obługi zdarzenia :
procedure TForm3.IdUDPServer1UDPRead(Sender: TObject; AData: TBytes;ABinding: TIdSocketHandle);
a powinno być :
procedure TForm3.IdUDPServer1UDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
...i w ten oto sposób delphi nie wie co TBytes.
Bardzo dobry artykuł!!! Tego mi było trzeba :)
Wielkie dzięki naoprawde fajny ort! mam nadzieje że będziesz rozwijał ten temat i dodawał nowe rzeczy (OBY jak NAJCZĘŚCIEJ).
NO ZAJECIE się tym problem to SUPER pomysł a im wiecej rzeczy będzie opisanych tym lepiej. Fajnie by było poczytać o jakimś SCHEMACIE jak powinna wygladać aplikacja Klient-serwer i z czego sie składać :D