Back to site
Since 2004, our University project has become the Internet's most widespread web hosting directory. Here we like to talk a lot about web development, networking and server security. It is, after all, our expertise. To make things better we've launched this science section with the free access to educational resources and important scientific material translated to different languages.

PHP Soket Programiranje, urađeno na Pravi Način ™


Christoph Hochstrasser

Šta je soket?

IP adresa je identifikacija mrežnog uređaja u okviru mreže, a broj porta je identifikacija mrežne aplikacije na host računaru.

Ove dve stvari na jedinstven način identifikuju mrežnu aplikaciju na računaru i nazivaju se Soket.

Dakle, kada pošaljemo paket na 127.0.0.1 i port 80,paket je poslat na uređaj 127.0.0.1 (vaš lokalni host), a zatim operativni sistem proverava da li se aplikacija povezala preko porta 80.

Ako je aplikacija povezana na portu 80,onda operativni sistem prosleđuje mrežni paket aplikaciji. Aplikacija zatim može da prihvati povezivanje. Ovo se povezuje na IP Adresu i Broj Porta koji je klijent poslao sa prvobitnim zahtevom.

Postoji više načina da se to uradi

Nažalost, postoje dva načina da radite Soket programiranje sa PHP-om:

  • Soket Ekstenzija: uprkos tome što nije omogućena čak ni po podrazumevanim podešavanjima PHP programiranja, većina autora se poziva na Soket Ekstenziju kada se govori o Soket programiranju. Po uputstvu se svrstava u "niski nivo" Soket API-a, a jedina stvar u kojoj je dobra, jeste da pruži API sličan C- jeziku. To su sve funkcije koje počinju sa socket_.

  • Strim Soketi: Od verzije 5.0.0 PHP-a, Strim ekstenzija (pružanje svih IO apstrakcija PHP-a) je u stanju da se pridruži i poveže sa mrežnim Soketima. Soket resursi koji su stvoreni koristeći strim ekstenziju se mogu koristiti sa skoro svim strim srodnim funkcijama, kao što su fgets, fread ili stream_get_contents, i prema tome za njih obezbediti pristup strimovima na jednostavan i praktičan način, kao što je rad sa Fajl objektima. Ove funkcije sve počinju sa stream_socket_ i to su one koje zaista želite da koristite.

Povezivanje sa SERVEROM

Povezivanje sa Serverom se vrši sa funkcijom stream_socket_client. Jedini obavezan argument je specifikacija soketa na koji želite da se povežete, i da vraća resource pri uspešnom izvršavanju ili false kada je greška.

Soket specifikacija je u obliku $protocol://$host:$port, gde je protokol jedan od sledećih:

  • tcp, za komunikaciju putem TCP-a , što se koristi od strane skoro svih uobičajenih internet protokola kao što su HTTP, FTP, SMTP, gde je potrebna pouzdanost.

  • udp

  • ili unix, koji se povezuje na Unix Soket, što je posebna vrsta mrežnog soketa, koji pripada mrežnom steku operativnog sistema. Malo je efikasniji, jer nijedan mrežni interfejs nije uključen.

Možete pročitati više o podržanim soket transportima za stream_socket_ funkcije u Priručniku.

Evo jednostavnog primera za izradu HTTP zahteva:

<?php $addr = gethostbyname("www.example.com"); $client = stream_socket_client("tcp://$addr:80", $errno, $errorMessage); if ($client === false) { throw new UnexpectedValueException("Failed to connect: $errorMessage"); } fwrite($client, "GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n"); echo stream_get_contents($client); fclose($client);

Prođimo kroz ovo, korak po korak.

$addr = gethostbyname("www.example.com");

Prvo je potrebna IP adresa hosta na koji želite da se povežete. To se radi sa gethostbyname funkcijom.

$client = stream_socket_client("tcp://$addr:80", $errno, $errorMessage); if ($client === false) { throw new UnexpectedValueException("Failed to connect: $errorMessage"); }

Onda kreiramo soket konekciju sa stream_socket_client. Kada se vraća false, to znači da postoji greška - pa bacamo izuzetak. stream_socket_client prihvata reference kao drugi i treći argument, koje se potom postavljaju kao kod greške i poruka o grešci kada se greška pojavi.

fwrite($client, "GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n"); echo stream_get_contents($client);

Soket konekcije napravljene koristeći stream_socket_client su strimovi, upravo kao i datoteke otvorene koristeći fopen.To znači da možemo da koristimo fwrite za pisanje bajtova u soket i možemo da iskoristimo pogodnu stream_get_contents funkciju za čitanje celog odgovora.

fclose($client);

Strim soketi mogu da se zatvore, baš kao i datoteke koristeći, fclose.

SERVERI

Strim ekstenzija takođe pruža jednostavan način za pravljenje soket servera koristeći stream_socket_server funkciju.

Funkcija stream_socket_server, takođe, uzima soket specifikaciju kao prvi argument, u istom formatu kao i string prosleđen na stream_socket_client.

Održavanje servera uključuje najmanje sledeće tačke:

  1. pridruži se na Soket - govori operativnom sistemu da smo zainteresovani za mrežne pakete koji stižu na dati mrežni interfejs i port (= soket)

  2. Proveri da li je dolazna veza dostupna

  3. "Prihvati" dolazne veze (sa stream_socket_accept).

  4. Pošalji nešto korisno nazad klijentu

  5. Zatvori konekciju ili pusti da je klijent zatvori

  6. Idi na (2)

Prilikom pisanja servera, prvo morate da uradite "Accept" operaciju na server soketu. To se radi sa stream_socket_accept funkcijom. Ova funkcija blokira dok se klijent ne poveže sa serverom, ili dok tajm-aut ne istekne.

Evo jednostavnog eho servera:

<?php # server.php $server = stream_socket_server("tcp://127.0.0.1:1337", $errno, $errorMessage); if ($server === false) { throw new UnexpectedValueException("Could not bind to socket: $errorMessage"); } for (;;) { $client = @stream_socket_accept($server); if ($client) { stream_copy_to_stream($client, $client); fclose($client); } }

Možete pokušati ovo tako što ćete prvo pokrenuti svoju skriptu:

php server.php

Onda otvorite drugi terminal i ukucajte ovo:

% echo "Hello World" | nc 127.0.0.1 1337 Hello World

windows users: možete da otvorite telnet konekciju na 127.0.0.1 i port 1337, ukucate nešto i pritisnite ENTER. Trebalo bi da se pojavi isti tekst.

Hajde da prođemo kroz ovo, korak po korak:

$server = stream_socket_server("tcp://127.0.0.1:1337", $errno, $errorMessage);

Prvo se pridružite na tcp soket na adresi 127.0.0.1 i port 1337. To je mrežni soket, koji se može koristiti od strane klijenata za povezivanje na naš server. Baš kao i stream_socket_client, dva argumenta mogu biti prihvaćena po referenci, koji se zatim popunjavaju sa brojem greške i porukom o grešci koju može da pročita čovek.

if ($server === false) { throw new UnexpectedValueException("Could not bind to socket: $errorMessage"); }

Kada se greška pojavi, funkcija vraća false, tako da ovde prestajemo sa bacanjem izuzetka. Nema smisla da počinjemo sa čekanjem na povezivanje kada nismo mogli da se registrujemo za soket.

for (;;) {

Korišćenje for bez iskaza dovodi do beskonačne petlje. Ovo nam je potrebno, jer server treba da radi sve dok ne odlučimo da ga “ubijemo”.

$client = @stream_socket_accept($server);

stream_socket_accept blokira sve dok se klijent ne poveže sa soketom ili dok tajm-aut ne istekne. Suzbijanje grešaka je ovde namerno, jer ova funkcija voli da izbacuje nepotrebna upozorenja.

if ($client) {

Pozivanje stream_socket_accept ili vraća konekciju ili null kada tajm-aut istekne. Dakle, mi želimo da uradimo nešto, samo kada je klijent zapravo povezan, a to je, kada je povratna vrednost “truthy”.

stream_copy_to_stream($client, $client);

Ova dragocena funkcija je veoma praktična za naš eho server. Ona kopira bajtove iz strima koji je dat kao prvi argument, do strima datog kao drugi argument. Tako da zapravo vraća sve, što je klijent poslao.

fclose($client);

Poslednje, ali ne i najmanje važno, raskidamo vezu sa klijentom. Ovo nije uvek potrebno, jer u nekim slučajevima želite da pustite da klijent prekine vezu (npr. FTP).





Published (Last edited): 08-05-2013 , source: http://christophh.net/2012/07/24/php-socket-programming/