Delphi üzenetek küldése. Delphi

Delphi üzenetek küldése. Delphi

Üzenetfeldolgozási sorrend a Delphiben
Minden Delphi-osztály rendelkezik beépített üzenetkezelő mechanizmussal, amelyet üzenetkezelőknek neveznek. Az osztály üzenetet kap, és a kapott üzenettől függően meghívja a meghatározott metódusok egyikét. Ha a megfelelő metódus nincs megadva, akkor az alapértelmezett kezelő kerül meghívásra. Részletesebben, ez a mechanizmus a következőképpen működik.

Egy üzenet beérkezése után a VCL üzenetküldő rendszer sok előmunkát végez annak feldolgozása érdekében.

Ahogy fentebb megjegyeztük, az üzenetet kezdetben a TApplication.ProcessMessage metódus dolgozza fel, amely kiválasztja azt a fő üzenethurok sorából. Ezzel egyidejűleg ellenőrzi az FOnMessage mező tartalmát (valójában ellenőrzi az OnMessage esemény kezelőjének jelenlétét), és ha nem üres, akkor felhívja a kezelőt ehhez az eseményhez, és ha a mező üres ( Nil), majd meghívja a DispatchMessage(Msg) API függvényt. Ez nem történik meg üzenet küldésekor.

Ha az OnMessage eseménykezelő nincs megadva, akkor a DispatchMessage API függvény meghívásra kerül a fogadott üzenet feldolgozására, amely továbbítja az üzenetet az ablak fő eljárásának.

Tekintsük az üzenetfeldolgozási ciklust, miután megérkezik az összetevő főablakába. Az üzenetfeldolgozási sorrend a következő ábrán látható:

Látható, hogy az üzenet átkerül a MainWndProc-nak, majd a WndProc-nak, majd a Dispatch-nek, majd a DefaultHandler-nek.

A Delphinek van egy fő nem virtuális módszere MainWndProc(Var Message: TMessage) az egyes összetevők ablakához. Tartalmaz egy kivételkezelő blokkot, amely átadja az üzenetstruktúrát a Windowsból a WindowProc tulajdonságban meghatározott virtuális metódusnak. Ez a metódus azonban az alkalmazás HandleException metódusának meghívásával kezeli az üzenetfeldolgozás során előforduló kivételeket. Erről a helyről kiindulva biztosíthatja különleges bánásmódüzeneteket, ha a program logikája megköveteli. Általában ebben a szakaszban a feldolgozást megváltoztatják, hogy megakadályozzák a szabványos VCL feldolgozást.

Alapértelmezés szerint az objektum WindowProc tulajdonságának értéke a WndProc virtuális metódus címére inicializálódik. Továbbá, ha nincsenek regisztrált TWindowHook üzenethorogok, a WndProc meghívja a TObject.Dispatch virtuális metódust, amely a bejövő üzenetstruktúra Msg mezőjének használatával meghatározza, hogy ez az üzenet szerepel-e az üzenetkezelők listájában ezt a tárgyat. Ha az objektum nem kezeli az üzenetet, a rendszer megvizsgálja az ős üzenetkezelők listáját. Ha végül találunk ilyen metódust, akkor meghívjuk, ellenkező esetben a DefaultHandler virtuális metódust.

Végül az üzenet eljut a megfelelő feldolgozási eljáráshoz, ahol a neki szánt feldolgozás végrehajtásra kerül. Használva kulcsszóÖröklött tovább küldik feldolgozásra az ősöknél. Ezt követően az üzenet a DefaultHandler metódusba is bekerül, amely elvégzi az üzenetfeldolgozás utolsó műveleteit, és átadja a DefWindowProc (DefMDIProc) eljárásnak a szabványos Windows-feldolgozáshoz.

Üzenetek kezelése Delphi komponensekkel
És így, Rövid leírásüzenetfeldolgozási sorrend a következő. Kezdetben minden üzenet átmegy azon a metóduson, amelynek címe a WindowProc tulajdonságban van megadva. Alapértelmezés szerint ez a WndProc metódus. Ezt követően az üzenetmódszereik szerint szétválasztják és elküldik őket. A végén ismét konvergálnak a DefaultHandler metódusban, ha korábban nem dolgozták fel őket, vagy ha az örökölt kezelő (Inherited) meghívásra kerül a kezelőkben. Ezért a Delphi összetevői a következő képességekkel rendelkeznek az üzenetek kezelésére:
a) Mielőtt bármely üzenetkezelő látná az üzenetet. Ebben az esetben vagy a WindowProc tulajdonság metóduscímének cseréje, vagy a TControl.WndProc metódus cseréje szükséges.
A WindowProc tulajdonság a következőképpen van deklarálva:

Toure TWndMethod= eljárást(Var üzenet: TMessage) tárgy;
ingatlan WindowProc: TWndMethod;

Valójában a WindowProc tulajdonság használatával létrehozhat egy TWndMethod típusú metódust, és ideiglenesen lecserélheti az eredeti metódust a létrehozottra, azonban mivel a metódus címe nem kerül tárolásra a WindowProc tulajdonságban, először el kell tárolnia az eredeti metódus címét. WndProc módszerrel, hogy később vissza lehessen állítani.

OldWndProc: TWndMethod;
procedúra NewWndProc(var Üzenet: TMessage);
procedúra TForm1.NewWndProc(var Üzenet: TMessage);
var Ch: char;
kezdődik
if message.Msg= WM_MOUSEMOVE then start
Edit1.Text:='x='+inttostr(üzenet.LParamLo)+', y='+inttostr(üzenet.LParamHi);
vége
else WndProc(Üzenet);
vége;

eljárás TForm1.FormCreate(Sender: TObject);
kezdődik
OldWndProc:=WindowProc;
vége;

eljárás TForm1.CheckBox1Click(Sender: TObject);
kezdődik
Ha CheckBox1.Checked, akkor WindowProc:= NewWndProc
else WindowProc:= OldWndProc;
vége;

b) A megfelelő üzenetmódszeren belül.
Vegyünk egy másik hasonló példát.
A WMPAINT újrarajzolásához használja az összetevőknek küldött üzenetet.

A TForml osztályban deklaráljuk ezt a metódust, hogy felülbírálhassuk, és bemutatjuk a felülbírált üzenetmódszer megvalósítását:

Típus TForml=Osztály(TForm)
… // Minden egyéb szükséges nyilatkozat
védett
Eljárás WMPaint(Var Msg: TWMPaint); Üzenet WM_PAINT; vége;
Eljárás TForml.WMPaint(Var Msg: TWMPaint); Kezdődik
Ha CheckBox1.Checked Then ShowMessage('O6pa6o üzenetellenőrző!');
Örökölt;
vége;

Egyes üzenetkezelők felülbírálásakor mindig célszerű az Inherited meghívása a Windows számára szükséges alapvető üzenetfeldolgozás végrehajtásához.

c) Miután az üzenetnek megfelelő metódusok mindegyike látja.

Ebben az esetben felül kell írnia a DefaultHandlert.

eljárás DefaultHandler(varMessage); felülírás;
procedúra TForm1.DefaultHandler(var Message);
var i:integer;
kezdődik
ha Cardinal(Message)=WM_defh akkor
az i:= 0 és 10 között kezdődik
sípolás;
alvás(100);
vége
más
örökölt;
vége;

eljárás TForm1.Button5Click(Sender: TObject);
kezdődik
SendMessage(Handle,WM_defh,0,0);
vége;

Kommunikáció üzenetek és események között
Sok Delphi VCL esemény közvetlenül kapcsolódik a Windows üzenetekhez. BAN BEN súgórendszer A Delphi felsorolja ezeket a meccseket. táblázatban mutatjuk be.1.

Asztal 1

VCL eseményWindows üzenetVCL eseményWindows üzenet
OnActivateWM_ACTIVATEOnKeyPressWM_CHAR
kattintásraWM_LBUTTONDOWNOnKeyUpWM_KEYUP
OnCreateWM_CREATEOnPaintWM_PAINT
OnDblClickWM_LBUTTONDBLCLKOnResizeWM_SIZE
OnKeyDownWM_KEYDOWNOnTimerWM_TIMER

Ne hozzon létre üzenetkezelőket, ha van hozzá előre meghatározott esemény. Ezekben az esetekben célszerű az eseménykezelést használni, mert az kevésbé korlátozó.

Alkalmazások fejlesztése során előfordulhat olyan helyzet, amikor egy alkalmazásnak üzenetet kell küldenie akár magának, akár egy másik felhasználói alkalmazásnak. Lehet, hogy néhányan értetlenül állnak az előző kijelentés előtt: miért kellene egy alkalmazásnak üzenetet küldenie magának, ha egyszerűen meghívhatja a megfelelő eljárást? Ez jó kérdés, és több válasz is létezik rá. Először is, az üzenetek használata egy olyan mechanizmus, amely támogatja a valódi polimorfizmust, mivel nem követeli meg az üzenetet fogadó objektum típusának ismeretét. Így az üzenetküldési technológia ugyanolyan erővel rendelkezik, mint a virtuális módszer mechanizmus, de sokkal rugalmasabb. Másodszor, az üzenetek lehetővé teszik az opcionális feldolgozást - ha a címzett objektum nem dolgozza fel a bejövő üzenetet, akkor semmi szörnyű nem történik. És harmadszor, az üzenetek lehetővé teszik több címzettnek történő sugárzást és párhuzamos hallgatást, amit meglehetősen nehéz megvalósítani az eljáráshívási mechanizmus segítségével.

Üzenetek használata egy alkalmazáson belül

Egy alkalmazás üzenetet küldeni önmagának nagyon egyszerű - csak használja a funkciókat API interfész Win32 SendMessage() vagy PostMessage(), vagy a Perform() metódus. Az üzenet azonosítójának a WM_USER+100 és $7FFFF tartományban kell lennie (amelyet a Windows a felhasználói üzenetek számára tart fenn). Például: const

SX_MYMESSAGE = WM_USER + 100;

SomeForm.Perform(SX_MY MESSAGE, 0, 0);

Üzenet küldése(SomeForm.Handle, SX_MY MESSAGE, 0, 0);

PostMessage(SomeForm.Handle, SX_MY MESSAGE, 0, 0);

Ezután az üzenet elfogásához hozzon létre egy normál kezelői eljárást, amely végrehajtja a szükséges műveleteket a következő formában:

TForm1 = osztály(TForm)

procedúra SXMyMessage(var Msg: TMessage); üzenet SX_MYMESSAGE;

procedúra TForm1.SXMyMessage(var Msg: TMessage);

MessageDlg('Getévé változtatott!',

mtInformáció, , 0);

Amint a példából látható, kevés különbség van a natív üzenetek feldolgozása között a szabványos Windows-üzenetektől. Ezek a WM_USER+100 és afölötti azonosítók használatából állnak, valamint minden üzenetnek olyan nevet adnak, amely valamilyen módon tükrözi a jelentését.

Soha ne küldjön 7 FFF-nél nagyobb WM_USER értékű üzenetet, hacsak nem biztos abban, hogy a címzett képes megfelelően feldolgozni az üzenetet. Mivel minden ablak önállóan választhatja ki az általa használt értékeket, nagyon valószínű, hogy finom hibák fordulnak elő, hacsak nem hoz létre előre üzenetazonosító táblázatokat, amelyekkel az üzenetek küldője és fogadója együtt fog működni.

Üzenetküldés az alkalmazások között

Ha két vagy több alkalmazás között kell üzenetet váltania, akkor ezekben a RegisterWindowMessage() API függvényt kell használnia. Ez a módszer biztosítja, hogy egy adott üzenettípushoz minden alkalmazás ugyanazt használja üzenet száma(üzenetszám).

A RegisterWindowMessage() függvény paraméterként egy karakterláncot vesz fel

null karakterrel fejeződik be, és egy azonosítót ad vissza a $C000 - $FFFF tartományban az új üzenethez. Ez azt jelenti, hogy ezt a függvényt bármely alkalmazásban paraméterként ugyanazzal a karakterlánccal hívjuk meg, hogy ugyanazt az üzenetszámot garantáljuk a cserében részt vevő összes alkalmazásban. Egy ilyen funkció másik előnye, hogy a rendszer garantálja, hogy az adott sorhoz rendelt azonosító egyedi legyen. Ez lehetővé teszi a szórási üzenetek elküldését a rendszer összes létező ablakába anélkül, hogy félne a nem kívánt üzenetektől mellékhatások. hátrány ez a módszer az ilyen üzenetek feldolgozása némi bonyodalmat okoz. A lényeg az, hogy az üzenetazonosítót csak akkor ismerjük, amikor az alkalmazás fut, így a szabványos üzenetkezelési rutinok használata nem lehetséges. Az ilyen üzenetek kezeléséhez újra kell definiálni szabványos módszerek WndProc() vagy DefaultHandler() vezérlők, vagy a megfelelő ablakosztály-eljárások.

MEGJEGYZÉSRE

A RegisterWindowMessage() függvény által visszaadott szám dinamikusan generálódik, és eltarthat különféle jelentések különbözőben Windows munkamenetek, ami azt jelenti, hogy nem határozható meg, amíg a program le nem fut.

Üzenetek közvetítése

A TWinControl osztályból származó bármely osztály lehetővé teszi a Broadcast() metódus használatát a küldéshez adásüzenet(üzenet közvetítése) bármely olyan vezérlőhöz, amelynek a tulajdonosa. Ezt a technikát akkor használják, ha ugyanazt az üzenetet kell elküldeni az összetevők egy csoportjának. Ha például egy um_Foo nevű egyéni üzenetet szeretne küldeni a Panel1 objektumhoz tartozó összes vezérlőnek, a következő kódot használhatja:

Üzenet:= UM_FOO;

Készítsen olyan programot, amely interfészt biztosít a Win2000/XP szabványos net send messaging parancs használatához. A felhasználó megadhatja a címzett címét, az üzenet szövegét és a küldendő üzenetek számát. Lehetőséget kell biztosítani egy blokk beállítására is, hogy üzeneteket fogadhasson más számítógépekről.

Formafejlesztés

Hozzon létre egy új Delphi projektet. Módosítsa az űrlap címét (Felirat tulajdonság) Net Sender értékre. Helyezzen egymás fölé a kategória három Címke komponensét az űrlap bal széle mentén alapértelmezettés állítsa be a Caption tulajdonságukat IP-cím:, Message: és Quantity: értékre.

Minden címke mellé helyezze el a kategória Szerkesztés összetevőjét alapértelmezett. Nevezze el a legfelső ip-t (Name tulajdonság), és rendelje hozzá a 192.168.0.1 értéket a Text tulajdonsághoz; nevezze el a középső mezőt txt-nek, és rendeljen hozzá valamilyen alapértelmezett üzenetszöveget a Szöveg tulajdonsághoz; Nevezze el az alsó mezőt hogyan, és állítsa a Szöveg tulajdonságot 1-re.

A felsorolt ​​összetevők alatt helyezze el a Checkbox összetevő kategóriát alapértelmezett. Nevezze biztonságosnak, állítsa a Caption tulajdonságot Üzenetek fogadásának letiltása értékre, és állítsa a Checked tulajdonságot True értékre.

Helyezzen egy gombot az űrlap aljára (a gomb komponense a alapértelmezett) a Caption tulajdonságának Send értékre állításával. Szükségünk van egy időzítőre is (a Timer összetevője a Rendszer), amelyhez az Intervallum tulajdonságot 10-re kell állítani.

A kapott formának meg kell felelnie a 2. ábrának. 15.1.

Rizs. 15.1. Űrlap a programhoz, amelyre üzeneteket küldhet helyi hálózat

Programkód fejlesztés

Először is írjuk meg a saját bomba eljárásunkat, amely minden beállítást elolvas és üzenetet küld. Jelenítse meg ezt az eljárást az űrlaposztály privát tagjaként:

Szükségünk van egy egész típusú globális i változóra is:

Most hozzuk létre a bomba eljárás megvalósítását a megvalósítási részben:

eljárás TForm1.bomb();
ha how.Text= "" then how.Text:= "1";
ha ip.Text = "" akkor ip.Text:= "127.0.0.1";(ha az ip-cím nincs megadva, akkor elküldjük a helyi számítógépre)
WinExec(PChar("net send " + ip.Szöveg + """ + txt.Szöveg + """), 0);//üzenet küldése

Ez az eljárás ellenőrzi, hogy minden kötelező mező ki van-e töltve. Ha nincs üzenet szövege, akkor állítsa be a "!" jelet; ha az IP-cím nincs megadva, akkor üzenetet küldünk a helyi számítógépnek a 127.0.0.1 címmel; ha az üzenetek száma nincs megadva, akkor egy üzenetet küldünk. Az üzenetek elküldése a szabványos net send paranccsal történik, amelynek szintaxisa a következő:

net küldjön ip cím üzenetet.

Most kezeljük az időzítő OnTimer eseményét:

h: HWND;//ablakazonosítót tárol
ha nem biztonságos.Akkor ellenőrizték//ha a jelölőnégyzet nincs bejelölve
Timer1.Enabled:= False;//figyelés letiltása
ha biztonságos.Akkor ellenőrizték//ha a jelölőnégyzet be van jelölve
//üzeneteket tartalmazó ablakok keresése
h:= FindWindow(nil, "Üzenetküldő szolgáltatás");// zárja be az összes talált ablakot
ha h<>

Ha az Üzenetek fogadásának letiltása jelölőnégyzet be van jelölve, akkor elkezdjük figyelni azokat az ablakokat, amelyeknek a címe szerint ez üzenet, és bezárjuk az összes talált ablakot. Ha a jelölőnégyzet nincs bejelölve, a figyelés le van tiltva.

A két mód közötti váltáshoz létre kell hoznia egy biztonságos.OnClick eseménykezelőt:

ha biztonságos.Akkor ellenőrizték//ha a jelölőnégyzet be van jelölve...
Timer1.Enabled:= True;//... figyelés engedélyezése

Amikor megnyom egy gombot Küld hívjuk a bombaeljárást:

A felhasználó életének megkönnyítése érdekében ügyelünk arra, hogy az üzenet a gomb megnyomásával is elküldésre kerüljön bármely szövegbeviteli mezőben. Ehhez létre kell hoznia egy OnKeyPress eseménykezelőt az egyes mezőkhöz. Ennek a kezelőnek a kódja az ip mezőhöz, amely azután hozzárendelhető a txt és hogyan mezőkhöz:

ha kulcs= #13 akkor//ha egy billentyűt lenyomnak
bomba;//üzenet küldése

Teljes modul forráskód

A LAN üzenetküldő program modul teljes kódja a 15.1-es listában látható.

Felsorolás 15.1. LAN üzenetküldő program modul

Windows, Üzenetek, SysUtils, Változatok, Osztályok, Grafika, Vezérlők, Űrlapok, Dialógusok, StdCtrl, ExtCtrl;

procedúra Timer1Timer(Sender: TObject);
procedúra safeClick(Sender: TObject);
procedúra ipKeyPress(Sender: TObject; var Kulcs: Char);
procedúra txtKeyPress(Küldő: TObject; var Kulcs: Char);
procedúra howKeyPress(Sender: TObject; var Kulcs: Char);
eljárás Button1Click(Sender: TObject);


// ellenőrizze, hogy a szöveges üzenet nem üres-e
if txt.Text = "" then txt.Text:= "!";
//ha a mennyiség nincs megadva, akkor küldjön egy üzenetet
if how.Text= "" then how.Text:= "1";
ha ip.Text = "" akkor ip.Text:= "127.0.0.1"; (ha az ip-cím nincs megadva, akkor elküldjük a helyi számítógépre)
//elküldi a megadott számú üzenetet
for i:=1 to StrToInt(how.Text) tegye
WinExec(PChar("net send " + ip.Szöveg + """ + txt.Szöveg + """), 0); //üzenet küldése

eljárás TForm1.Timer1Timer(Küldő: TObject);
h: HWND; //ablakazonosítót tárol
ha nem biztonságos.Checked then //ha a jelölőnégyzet nincs bejelölve
Timer1.Enabled:= False; //figyelés letiltása
ha biztonságos.Checked then //ha a jelölőnégyzet be van jelölve
//üzeneteket tartalmazó ablakok keresése
h:= FindWindow(nil, "Üzenetküldő szolgáltatás"); // zárja be az összes talált ablakot
ha h<>0, majd PostMessage(h, WM_QUIT, 0, 0);

eljárás TForm1.secureClick(Sender: TObject);
ha biztonságos.Checked then //ha a jelölőnégyzet be van jelölve...
Timer1.Enabled:= True; //... figyelés engedélyezése

procedúra TForm1.ipKeyPress(Sender: TObject; var Kulcs: Char);
ha kulcs = #13, akkor //ha egy billentyűt lenyomnak
bomba; //üzenet küldése

eljárás TForm1.Button1Click(Sender: TObject);

⊚ Az összes projektfájl és a szóban forgó program végrehajtható fájlja a könyvhöz mellékelt CD-n, a 15. fejezet mappában található.

A delphi programok gyakran e-mailt használnak. Ez a cikk részletesen elmagyarázza, hogyan küldik el e-mailjeit egy másik felhasználónak. delphi használatával. Ebben az esetben csak szabványos Delphi komponenseket fogunk használni.

Kezdésként hozzunk létre egy új projektet, és nevezzük el \"E-mailek küldése delphi használatával\". Ezután több komponenst 1x Memo, 3x Edit, 2x Botton át kell vinni az űrlapra, illetve át kell vinni az IdSMTP, IdAntiFreeze, IdMessage elemeket is. Ezután bármelyik gomb onclick eseményére írjuk:

//választ SMTP szerver. BAN BEN Ebben a pillanatban költségek yandex. IdSMTP1.Host:= "smtp.yandex.ru"; //a bejelentkezési neve (egyeseknek domainnel kell írni). IdSMTP1.Felhasználónév:=" [e-mail védett]"; //mail jelszó. IdSMTP1.Password:= "qwerty123"; //port, az 587 használatát javasoljuk. IdSMTP1.Port:=587; //az üzenet tárgya belefér a Szerkesztés2-be. IdMessage1.Subject:= Edit2 .Text; // Az Edit1 tartalmazza a címzett címét. IdMessage1.Recipients.EMailAddresses:= Edit1.Text; //az Ön e-mailje, ahonnan a feladó megy. IdMessage1.From.Address:= " [e-mail védett]"; // a memo1 tartalmazza az elküldeni kívánt szöveget. IdMessage1.Body.Text:= memo1.Text ; // Az Edit3 tartalmazza a Elektronikus aláírás(Név). IdMessage1.From.Name:= Edit3.Text; //csatlakozás IdSMTP1.connect; //Send IdSMTP1.Send(IdMessage1); //lekapcsolódás IdSMTP1.Disconnect;

Ha az IdMessage kérdőjeleket jelenít meg

Ez a hiba azzal kapcsolatos, hogy orosz betűket ír be, és a memo komponens nem tudja helyesen olvasni őket, ehhez meg kell adnia az Utf8 kódolást.

// kódolás beállítása IdMessage1.Charset:="UTF-8"; // lefordítja a szöveget a szükséges kódolásra IdMessage1.Body.Text:=UTF8Encode(memo1.text);

valahol olyan

IdTCPClient1.Host:= "127.0.0.1"; IdTCPClient1.Connect;// csatlakoztatva IdTCPClient1.Socket.WriteLn("command"); // parancs elküldve a parancsot és a soremelést //Várja meg a választ, és zárja be a kapcsolatot txtResults.Lines.Append(IdTCPClient1.Socket.ReadLn); IdTCPClient1.Disconnect;

ebben az esetben a parancs csak szöveg újsorral. Ez sokkal könnyebbé teszi a parancs fogadását a másik oldalról (csak ReadLn). Általános esetben ki kell találni (vagy kész) protokollt kell használni.

felette egy ügyfél volt. És most a szerver. A szerverrel a dolgok kicsit bonyolultabbak. Nyilvánvaló, hogy normális, ha egy szerver egynél több ügyfelet szolgál ki. És erre több "séma" is létezik.

    Klasszikus – egy ügyfél – egy szál. Az áramkör könnyen kódolható, intuitív. Jól párhuzamos a magok között. Hátránya, hogy általában nagyon nehéz sok szálat létrehozni, és ez korlátozza az ügyfelek számát. A 32 bites programok esetében a felső határ valahol 1500 (másfél ezer) szál körül van folyamatonként. De ebben az esetben a váltás rezsije a teljes százalékot "megeheti". Ez az indyben használt séma.

    A második klasszikus - minden ügyfél egy áramlásban. Ez a séma gyakran bonyolultabb a kódolásban, de megfelelő megközelítéssel lehetővé teszi 20-30 ezer "lassú felhasználó" megtartását, gyakorlatilag a mag terhelése nélkül. Ennek a sémának az erős előnye, hogy mutexet és egyéb szinkronizálási primitíveket nélkülözhet. Ezt a sémát a NodeJS és a szabványos osztályok használják a Qt-ben történő hálózatépítéshez.

    Vegyes. Ebben az esetben több szál jön létre, amelyek mindegyike bizonyos számú ügyfelet szolgál ki. A legnehezebb a kódolásban, de lehetővé teszi a vasforrások maximális kihasználását.

Hogyan csinálják Indyben. Az Indy tcp szerver minden kapcsolathoz külön szálat (TThread) hoz létre és további munka a kliens bemegy benne. Az Indy ezt szépen elrejti, így csak a felhasználónak kell megvalósítania az IdTCPServer.onExecute metódust. De amint fentebb mondtam, ez a módszer egy külön szálban indul, és minden ügyfélnek megvan a saját személyes. Ez a következőket jelenti:

  • Ezzel a módszerrel az alvás hívható, és csak egy ügyfél vár. Az összes többi működni fog (de ha a gombkattintás kezelőben hívja az alvást, akkor ismert az eredmény)
    • jobb a globális változókhoz csak szinkronizációs primitíveken keresztül hozzáférni.
    • a gui elemeket óvatosan és helyesen kell kezelni. Jobb, ha nem csinálja közvetlenül (egyes összetevők lehetővé teszik, hogy más szálakból is hozzáférjenek hozzájuk, de figyelmesen el kell olvasnia a dokkokat).
    • záron keresztül kell elérni a többi klienst (mert ha két szál ugyanannak a felhasználónak akar írni, abból semmi jó nem lesz).

Nézzünk egy nagyon egyszerű példát. Minden kliens kérésre ugyanúgy válaszolunk, és lezárjuk a kapcsolatot (ilyen echo szerver).

Eljárás TForm1.IdTCPServer1Execute(AContext: TIdContext); var strText: String; begin //Karakterlánc fogadása az ügyféltől strText:= AContext.Connection.Socket.ReadLn; //Válasz AContext.Connection.Socket.WriteLn(strText); //Kapcsolat bezárása a felhasználóval AContext.Connection.Disconnect; vége;

Az AContext egy speciális objektum, amely minden szükséges információt tartalmaz az ügyfélről. Maga az idTcpServer tartalmazza ezen kontextusok listáját, és elérhető. Nézzünk egy bonyolultabb adást. Vagyis küldjön egy üzenetet mindenkinek

VarClients:TList; i: egész szám; begin // bolondbiztos :) ha nem Assigned(IdTCPServer1.Contexts) akkor kilép; // kap egy listát az ügyfelekről, és zárolja azt Clients:=IdTCPServer1.Contexts.LockList; try for i:= 0 to Clients.Count-1 do try //Az LBuffer TBytes típusú, és küldésre előkészített adatokat tartalmaz // de a WriteLn is használható. TIdContext(Clients[i]).Connection.IOHandler.Write(LBuffer); kivéve // ​​a logikát ide kell hozzáadni. A kliens megszakíthatja a kapcsolatot a végén; végre // fontos! a listát fel kell oldani, különben más módszerek nem léphetnek túl a Contexts.LockList IdTCPServer1.Contexts.UnlockList; vége; vége;

Az indie tartalmazza a BytesToString() és ToBytes() függvényeket a String és a TIdByte egymásba konvertálásához.

A lista zárolva van, így mások nem módosíthatják. Ellenkező esetben maga a ciklus sokkal bonyolultabbá válik. És ami a legfontosabb, ne felejtsd el kinyitni!

Az utolsó kérdés marad. Hogyan lehet üzenetet küldeni egy adott ügyfélnek. Ehhez meg kell tanulnia a kapcsolat azonosítását. Ezt többféleképpen is meg lehet tenni – nézd meg az ip/portot. De van jobb is. Az IdContext (pontosabban az őse idTask) TObject típusú Data tulajdonsággal rendelkezik. Beírhatja az objektumát, és ott tárolhatja az összes szükséges adatot. Tipikus példa használat lesz a következő. Amikor az ügyfél éppen csatlakozott, ez a mező üres. Amikor átment a név-jelszó ellenőrzésen, létrehozunk egy objektumot (saját), elmentjük a nevet, és beírjuk a Data property-be. Aztán amikor át kell lépnie a csatlakoztatott klienseken, egyszerűen kivonjuk. Természetesen, ha több ezer felhasználó van, akkor minden alkalommal költséges lesz az összes felhasználó megtekintése. De hogyan lehet ezt optimálisabban csinálni, az egy másik nagy cikk témája.