În prima parte, dedicată principiilor de utilizare a soclurilor MSWindows în programele de asamblare, am vorbit despre ce socket-uri sunt, cum sunt create și ce parametri sunt preluați. În același timp, a fost menționată ocazional despre protocolul UDP orientat fără conexiune, care nu garantează livrarea pachetelor, precum și ordinea sosirii lor la destinație. În acest exemplu, a fost utilizat protocolul TCP preferat. Și totul a fost bine cu noi, dar în cele din urmă au existat o serie de probleme nerezolvate, în special, cum să organizăm un schimb reciproc între mai multe computere din rețea, cum să transferăm ceva direct la mai multe computere etc.
În general, citirea primei părți pentru a înțelege curentul nu este necesară, deși în cursul acestei chestiuni mă voi referi în mod constant la aceasta. Astfel de cazuri. Haha.
Deci, ne-am stabilit sarcina: există o rețea locală, de exemplu, de o duzină de calculatoare, aveți nevoie pentru a organiza un schimb de mesaje între oricare două dintre ele, și (opțional) între unul și toți ceilalți.
Am auzit, aud un cor de indicii pe care le spun, folosiți caracteristicile încorporate ale Windows, cum ar fi:
net trimite 192.168.0.4 Zhenya vă trimite salutări!
net trimite Node4 Aștept răspuns!
Există doar două obiecții față de aceasta. În primul rând, nu este suficient ca sistemul nostru de operare sau alte programe gata făcute să poată, să vrem să învățăm cum să scriem programele noastre, nu-i așa? Și a doua, nu faptul că mesajul merge de la o persoană la alta. În general, operatorul poate să nu știe nimic. Și atunci nu ar trebui să știu nimic.
Pentru mine, cel mai important lucru în stabilirea acestei sarcini a fost de a oferi posibilitatea de a transfera ceva la toate calculatoarele din rețea dintr-o dată. Imaginați-vă că am scris un anumit program. Cine a spus - Troian? Nu, nu și nu! Nu troiani. Doar un mic (foarte) program contabil, de exemplu. Cine ar putea mai rămâne după o perioadă de timp să se stabilească pe mai multe computere din rețeaua noastră locală. Și acum vine momentul potrivit, este timpul să reducem echilibrul de la buldoză, să rezumăm, ca să spunem așa, rezultatul pentru trimestru. Trebuie să facem totul rapid și preferabil simultan. Cum să facem acest lucru în cadrul materialului pe care l-am studiat în prima parte a rămas neclar.
Schema de interacțiune a protocoalelor de rețea.
TCP - Transmission C ontrol P rotocol
ICMP - Protocolul de transmitere a informațiilor pe Internet (protocol de mesagerie)
În general, dacă desenul nu te-a ajutat, nu contează. Este important să înțelegem un lucru: TCP este un protocol de nivel de transport care asigură transportul fiabil de date între procesele de aplicație, prin stabilirea unei conexiuni logice (evidențiată de mine). Și UDP - nu. Și mai mult. Undeva acolo, la nivelul aplicației, într-unul din dreptunghiurile goale și va fi aplicația noastră.
Aceasta concluzionează partea introductivă și se îndreaptă spre examinarea modului de utilizare a acesteia, încă de la început.
Pentru a demonstra tot materialul, ca de obicei, folosiți un exemplu de instruire pe care îl puteți descărca <здесь>. Vom trece peste partea comună tuturor aplicațiilor Windows și vom descrie numai ce se referă la funcționarea soclurilor. În primul rând, trebuie să inițializați Windows Sockets DLL utilizând funcția WSAStartup (). care va reveni la zero dacă a reușit sau, altfel, la unul dintre codurile de eroare. Apoi, când inițializați fereastra principală a aplicației, deschideți soclul pentru primirea mesajelor:
Și dacă nu există nici o eroare, trebuie să salvați descriptorul socketului recepționat pentru utilizare ulterioară:
După aceasta, ca de obicei, trebuie să spuneți Windows să trimită mesaje către fereastra specificată din soclul pe care l-am deschis:
unde hSocket este mânerul soclului
hWnd - mâner fereastră, a cărui procedură va trimite mesaje
WM_SOCKET este mesajul definit în secțiunea .const
FD_READ este o mască care specifică evenimentele de care suntem interesați, în acest caz este disponibilitatea datelor din socket pentru citire.
sau, mai corect, folosiți:
După aceea, va fi lansată și aplicația noastră, va fi creată fereastra principală, un mesaj WM_CREATE va fi trimis din Windows cu toate cele ce urmează ... Doar ferestrele sale nu vor fi vizibile nici pe desktop, nici pe bara de activități. Dacă asta ai vrut, mă bucur. În orice caz, vom continua.
Pentru a face acest lucru, convertiți numărul de port într-o comandă de octet de rețea utilizând funcția API specială:
O mică digresiune lirică, care nu este necesară pentru a înțelege semnificația acestui articol.
Numerele porturilor pentru prizele noastre au fost discutate la sfârșitul primei părți. Este dificil să se dea recomandări cu privire la ceea ce ar trebui să fie. Singurul lucru pe care-l poți spune este că nu pot fi. Este nerezonabil să încercați să utilizați numere de port definite pentru servicii utilizate pe scară largă, cum ar fi:
prin intermediul protocolului TCP. 20, 21 - ftp; 23 - telnet; 25 - smtp; 80 - http; 139 - Serviciu de sesiune NetBIOS;
prin intermediul protocolului UDP. 53 - DNS; 137, 138 - NetBIOS; 161 - SNMP;
Desigur, API are o funcție specială numită getervbyport (). care prin numărul de port dat returnează numele serviciului care îi corespunde. Mai degrabă, funcția însăși readuce un pointer la o structură în interiorul căreia există un pointer la acest nume.
Puteți să-l numiți astfel:
Fiți atenți la ceea ce spune Win32 Programmer'sReference despre getervbyport:
“. Returnează un indicator la structura distribuită de Windows Sockets. Aplicația nu trebuie să încerce niciodată să modifice această structură sau oricare dintre componentele acesteia. În plus, o singură copie a acestei structuri este alocată fluxului, astfel încât aplicația trebuie să copieze orice informație de care are nevoie înainte de orice alt apel către funcția Windows Sockets. "
Și aici este structura:
Există un API, ca să spunem așa, și funcția "pereche": getervbyname (). care prin numele serviciului returnează informații despre numărul portului utilizat.
Din păcate, beneficiile practice ale acestor funcții nu pot fi extrase pentru noi. Deci, știți că există și uită de ele.
Această lucrare pregătitoare privind crearea și configurarea socketului de recepție utilizând datagrame poate fi considerată completă. Nu este necesar să setați soclul la starea de ascultare a portului cu ajutorul funcției invoke ascultare. așa cum am făcut pentru un socket ca SOCK_STREAM în prima parte. Acum, în procedura din fereastra principală a aplicației noastre, putem adăuga codul care va fi executat atunci când un mesaj WM_SOCKET sosește din socket:
Acum, cum să deschideți un soclu pentru trimiterea mesajelor. Iată toate acțiunile necesare ale programului:
Când vine vorba de transferul de date, este suficient să faceți următoarele:
Valorile parametrilor la apelarea acestei funcții sunt următoarele:
În cazul în care, atunci când sendto () funcționează fără erori, returnează numărul de octeți transferați, în caz contrar ieșire au în eaxznachenie SOCKET_ERROR.
De fapt, asta e tot. În momentul închiderii programului, trebuie să închideți prizele și să eliberați resursele DLL-urilor Sockets, acest lucru este ușor:
Pentru aplicațiile multi-threaded după WSACleanup, operațiile socket pentru toate firele sunt finalizate.
Cel mai dificil lucru din acest articol a fost pentru mine să hotărăsc cum să ilustrez cel mai bine utilizarea API-ului Windows Sockets. O abordare, pe care probabil ați văzut-o deja, când într-o singură aplicație au fost utilizate simultan atât o priză pentru recepție, cât și un soclu pentru trimiterea de mesaje. Nu mai puțin atractivă este o altă modalitate, atunci când codul pentru unul și celălalt este clar împărțit, până la ceea ce există în diferite aplicații. În cele din urmă, am realizat și această metodă, care poate fi mai ușor pentru începători de înțeles. În al doilea <архиве> se află dosarul:
\ SocSocDR - program de testare, doar partea de primire
\ SocSocDW - respectiv, numai partea de transmisie
Diferența, pe lângă cele deja menționate, este că în programul de trimitere, când selectați "Send test ..." în loc de funcția sendto (), folosim funcția send (), care ne este cunoscută în primul articol:
Această funcție () va reveni la SOCKET_ERROR!
În cele din urmă, există câteva probleme comune care apar atunci când lucrați cu prize. Pentru a procesa un mesaj de fereastră care ne informează că starea soclului s-a schimbat, noi, ca de obicei, am folosit mesaje directe de la Windows la fereastra principală a aplicației. Există o altă abordare atunci când creați ferestre separate pentru fiecare soclu.
În general vorbind, prelucrarea centralizată a mesajelor prin fereastra principală este, după cum se pare, o metodă mai simplă de înțeles, care, totuși, în practică poate adăuga la hassle. Dacă programul folosește mai mult de un singur soclu în același timp, trebuie să stocați o listă de descriptori de soclu. Când apare un mesaj din prize, procedura din fereastra principală din listă caută informațiile asociate cu acest descriptor socket și trimite un mesaj de stare mai departe la procedura destinată acestui lucru. Care reacționează deja într-un fel sau altul, face ceva acolo. Această abordare obligă procesarea sarcinilor de rețea să fie integrată în nucleul programului, ceea ce face dificilă crearea de biblioteci ale funcțiilor de rețea. De fiecare dată când se utilizează aceste funcții de rețea, trebuie adăugat un cod suplimentar în fereastra principală a dispozitivului de procesare a aplicației.
În a doua metodă de procesare a mesajelor pentru a le primi, aplicația creează o fereastră ascunsă. Acesta servește pentru a separa fereastra principală a aplicației de prelucrarea mesajelor de rețea. Această abordare poate simplifica aplicația principală și poate facilita utilizarea codului de rețea existent în alte programe. Partea negativă a acestei abordări este utilizarea excesivă a memoriei de utilizatori Windows, deoarece pentru fiecare fereastră creată este rezervată pentru o cantitate mare de ea.
În ce mod alegeți - decideți-vă singur. Și încă un lucru. Pe durata experimentelor, poate fi necesar să dezactivați firewall-ul personal. De exemplu, Outpost Pro 2.1.275 într-un mod de învățare pentru a reacționa la încercarea de a transfera o priză, dar atunci când transmisia este rezolvată manual, nu este încă atins datele. Iată pentru dvs. și UDP. Deși acest lucru nu poate fi cazul. Probleme cu ZoneAlarmPro 5.0.590 în aceeași situație nu a fost.