Vra

Wat is die normale manier waarop mense skryf netwerk-kode in Delphi gebruik Windows-styl oorvleuel asynchrone socket I/O?

Hier is my vorige navorsing in hierdie vraag:

Die Indy komponente lyk heeltemal sinchrone.Aan die ander kant, terwyl ScktComp eenheid nie gebruik WSAAsyncSelect, dit is basies net asynchronizes'n BSD-styl multiplexed socket app.Jy kry gestort in'n enkele gebeurtenis terugbel, so as jy het pas teruggekeer uit te kies() in'n lus, en het om te doen al die staat masjien navigasie jouself.

Die .NETTO situasie is aansienlik mooier, met Socket.BeginRead / Socket.EndRead, waar die voortsetting is verby direk na Socket.BeginRead, en dit is waar jy kies back-up.'n voortsetting gekodeer as'n sluiting natuurlik het al die konteks wat jy nodig het, en meer.

Was dit nuttig?

Ander wenke

Ek het gevind dat Indy, terwyl 'n eenvoudiger konsep in die begin, is ongemaklik om te bestuur as gevolg van die behoefte om voetstukke gratis drade dood by aansoek beëindiging. Daarbenewens, ek het die Indy biblioteek stop werk na 'n OS kol opgradering. ScktComp werk goed vir my aansoek.

@Roddy - Synchronous voetstukke is nie wat ek na. Brand 'n hele draad ter wille van 'n moontlik langlewende verband beteken dat jy die bedrag van parallelle verbindings te beperk tot die aantal drade wat jou proses kan bevat. Sedert drade gebruik baie van die hulpbronne - voorbehou stapel adres ruimte, verbind stapel geheue, en kern oorgange vir konteks skakel -. Hulle nie volgens skaal wanneer jy dit nodig om honderde verbindings, veel minder duisende of ondersteun meer

  

Wat is die normale manier waarop mense skryf   netwerk-kode in Delphi gebruik   Windows-styl oorvleuel asynchrone   socket I / O?

Wel, Indy het die "standaard" biblioteek vir aansluiting I / O vir 'n geruime tyd nou - en dit is gebaseer op die sluit voetstukke. Dit beteken as jy asynchrone gedrag wil, jy addisionele draad (s) gebruik om aan te sluit / lees / skryf data. Myns insiens is hierdie eintlik 'n groot voordeel, want daar is geen behoefte om enige soort van die staat masjien navigasie bestuur, of bekommerd wees oor terugbel procs of soortgelyke dinge. Ek vind die logika van my 'lees' draad is minder deurmekaar en nog baie meer draagbaar as nie-blokkeer voetstukke sou toelaat.

Indy 9 het meestal bomvrij, vinnige en betroubare vir ons. Maar die skuif na Indy 10 vir Tiburon veroorsaak vir my 'n bietjie kommer.

  

@Mike:. "... die behoefte om voetstukke doodmaak gratis drade ..."

Dit het gaan "huh?" totdat ek onthou ons threading biblioteek gebruik 'n-uitsondering gebaseer tegniek om dood te maak 'wag' drade veilig. Ons noem QueueUserAPC te ry 'n funksie wat verhoog 'n C ++ uitsondering (NIE afgelei van klas uitsondering) wat net moet gevang word deur ons draad wrapper prosedure. Alle destructors ontslae genoem so die drade al skoon te beëindig en netjies op die pad uit.

"Sinchrone voetstukke is nie wat ek is na."

Verstaan - maar ek dink in daardie geval is die antwoord op jou oorspronklike vraag is dat daar is nie net'n Delphi idioom vir async socket IO, want dit is eintlik'n hoogs gespesialiseerde en ongewoon vereiste.

As'n newe-kwessie, jy kan vind hierdie interessante skakels.Hulle is albei'n bietjie oud, en meer *nxy as Windows.Die tweede een impliseer dat - in die regte omgewing - drade dalk nie so sleg as wat jy dink.

Die C10K probleem

Hoekom Gebeure Is'n Slegte Idee (vir Hoë-gelyktydigheid Bedieners)

@Chris Miller -. Wat jy gesê in jou antwoord is feitelik onakkurate

Windows boodskap-styl asinkroniseer, as wat beskikbaar is deur WSAAsyncSelect, is inderdaad grootliks 'n oplossing vir 'n gebrek aan 'n behoorlike threading model in Win 3.x dae.

NET Begin / End is egter nie die gebruik van ekstra drade. In plaas daarvan, is dit met behulp van oorvleuel I / O, die gebruik van die ekstra argument op WSASend / WSARecv, spesifiek die oorvleuel voltooiing roetine, die voortsetting spesifiseer.

Dit beteken dat die NET styl maak gebruik van die Windows-bedryfstelsel se asinkroniseer I / O ondersteuning aan vermy brand 'n draad deur die sluit van 'n voetstuk.

Sedert drade oor die algemeen praat duur (tensy jy 'n baie klein stapel grootte te CreateThread spesifiseer), met drade blokkeer op voetstukke sal jy verhoed dat skalering om 10,000s van parallelle verbindings.

Dit is hoekom dit belangrik is dat asinkroniseer I / O gebruik word as jy wil volgens skaal, en ook waarom NET is nie , ek herhaal, is nie , eenvoudig "die gebruik van drade, [...] net deur die raamwerk".

@Roddy - Ek het reeds gelees die skakels wat jy verwys na, hulle albei gekla van Paul Tyma se aanbieding. "Duisende drade en Blokkering I / O - Die ou pad na Java Servers skryf is New weer"

Sommige van die dinge wat nie noodwendig uit nie spring van Paulus se aanbieding is egter dat hy gespesifiseerde -Xss: 48k na die JVM op opstart, en dat hy die veronderstelling dat NIO implementering die JVM se doeltreffende sodat dit aan wees van 'n geldige vergelyking.

Indy doen nie spesifiseer 'n soortgelyke verkrimp en styf beperk stapel grootte. Daar is geen oproepe na BeginThread (die Delphi RTL draad skepping roetine, wat jy moet gebruik vir sulke situasies) of CreateThread (die rou WinAPI oproep) in die Indy kodebasis.

Die standaard stapel grootte gestoor in die PE, en vir die Delphi samesteller dit standaard 1MB van gereserveerde adres ruimte (spasie is verbind per bladsy deur die bedryfstelsel in 4K stukke, in werklikheid, die samesteller moet-kode te genereer om raak bladsye indien daar> 4K van inwoners in 'n funksie, want die uitbreiding word beheer deur bladsy foute, maar net vir die laagste (wag) bladsy in die stapel). Dit beteken dat jy gaan uit adres ruimte om te hardloop na maksimum 2000 konkurrente drade hantering verbindings.

Nou, kan jy die standaard stapel grootte in die PE verander met behulp van die {$ M minStackSize [, maxStackSize]} richtlijn, maar wat 'n invloed sal al drade, insluitend die hoof draad. Ek hoop dat jy nie veel rekursie doen, omdat 48K of (soortgelyk) is nie 'n baie ruimte.

Nou, of Paulus is reg oor nie-prestasie van asinkroniseer I / O vir Windows in die besonder, ek is nie 100% seker - ek wil hê om te meet dit aan sekere wees. Wat ek wel weet, is egter dat argumente oor gestruktureerde programmering word makliker as asinkroniseer-gebeurtenis gebaseerde programmeertaal, is die aanbieding van 'n valse digotomie .

A-sinkroniseer kode nie behoefte om-gebeurtenis gebaseer wees; dit kan-voortsetting gebaseer wees, soos dit in NET, en as jy 'n sluiting as jou voortsetting spesifiseer, jy staat gehandhaaf vir jou gratis. Verder, omskakeling van lineêre draad-styl-kode vir voortsetting-afsterwe-styl asinkroniseer kode kan meganiese gemaak word deur 'n samesteller (CPS transformeer is meganiese), so daar hoef geen koste in kode duidelikheid wees nie.

Daar is 'n gratis IOCP (voltooiing hawens) socket komponente: http: // www .torry.net / authorsmore.php? id = 7131 (bronkode ingesluit)

  

"Deur Naberegnyh Sergey N .. High   prestasie socket bediener wat gebaseer is op   Windows Voltooiing Port en met behulp van   Windows Socket Uitbreidings. IPv6   ondersteun. "

Ek het dit gevind, terwyl op soek na 'n beter komponente / biblioteek om my bietjie klets bediener rearchitecture. Ek het dit nog nie probeer maar dit lyk goed gekodeer as 'n eerste indruk.

Indy gebruik sinchrone voetstukke, want dit is 'n eenvoudiger manier van ontwikkeling. Die asynchrone socket blokkeer was iets by die Winsock stapel terug in die Windows 3.x dae. Windows 3.x nie ondersteun drade en daar kan jy nie socket doen I / O sonder drade. Vir 'n paar ekstra inligting oor die rede waarom Indy maak gebruik van die blok model, sien asseblief hierdie artikel .

Die NET Socket.BeginRead / EndRead oproepe gebruik drade, is dit net deur die raamwerk plaas deur julle.

@Roddy, Indy 10 is saam met Delphi sedert by Delphi 2006 het ek gevind dat migreer vanaf Indy 9 tot Indy 10 tot 'n reguit vorentoe taak wees.

Met die ScktComp klasse, wat jy nodig het om te gebruik om'n ThreadBlocking bediener eerder as'n NonBlocking bediener tipe.Gebruik die OnGetThread gebeurtenis aan die hand van die ClientSocket param'n nuwe draad van jou bedink.Sodra jy het aangehaal'n geërf geval van TServerClientThread jy sal skep'n geval van TWinSocketStream (binne-in die draad) wat jy kan gebruik om te lees en skryf na die potjie.Hierdie metode kry jy weg van probeer om die proses van data in die gebeurtenis hanteerder.Hierdie drade kan bestaan net vir die kort tydperk nodig het om te lees of skryf nie, of hang op vir die duur vir die doel van hergebruik.

Die onderwerp van die skryf van'n socket bediener is redelik groot.Daar is baie tegnieke en praktyke jy kan kies om te implementeer.Die metode van lees en skryf aan die dieselfde socket met in die TServerClientThread is reguit vorentoe en boete vir die eenvoudige toepassings.As jy nodig het om'n model vir'n hoë beskikbaarheid en hoë gelyktydigheid dan moet jy om te kyk na die patrone soos die Proactor patroon.

Goeie geluk!

scroll top