LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> Perl (74) - Sockety

Perl Náplní dnešního dílu bude meziprogramová komunikace. Osvětlíme si pojem socket, jeho vlastnosti a nezbytnou součástí bude i názorná ukázka použití.

18.11.2008 06:00 | Jiří Václavík | Články autora | přečteno 11616×

Socket je virtuální spojení dvou procesů. Důležitě je zde slovo spojení. Z něj vyplývá to, že sockety jsou způsobem meziprocesorové komunikace. V praxi to znamená, že můžeme napsat dva programy, které spolu budou moci vzájemně komunikovat. První program - server - bude naslouchat na určeném portu (port je číslo reprezentující vstupní cestu do počítače) a bude čekat na přípojení druhého programu - klienta. V okamžiku, kdy se klient připojí, vznikne spojení a od této chvíle mohou obě strany komunikovat. Oba programy mohou běžet na různých počítačích, které jsou síťově propojeny.

Existují dva způsoby komunikace. Se spojením nebo beze spojení - tedy TCP nebo UDP. Typickým příkladem komunikace bez spojení je email. Mezi odesílatelem a příjemcem se nevytváří žádné spojení - odeslání emailu není závislé na příjemci a přijetí na odesílateli. Není zaručeno pořadí jednotlivých zpráv ani to, že někdo zprávu skutečně přijme. Naopak mezi komunikaci se spojením patří telefonní hovor. Oba účastnící jsou v jednom okamžiku spojeni komunikačním kanálem, který zaručuje správné pořadí zpráv.

Sockety v Perlu

V Perlu máme pro práci se sockety k dispozici moduly Socket a IO::Socket. My si představíme objektově orientovaný IO::Socket. Ten obsahuje dvě podtřídy. INET a UNIX. Prvně jmenovaná pro síťovou komunikaci a UNIX pro komunikaci lokální. O ní se však zmíníme jen letmo na konci. Máte-li zájem o modul Socket, nahlédněte do stránky man perlipc(1), jež se zabývá meziprocesorovou komunikací.

Příklad - jednoduchý chat

Jako nejjednodušší příklad aplikace s využitím socketů si napíšeme jednoduchý chat, pomocí kterého budou moci dva lidé připojení u různých počítačů ve stejné síti střídavě posílat zprávy.

Ještě než začneme si musíme ujasnit, co vlastně budeme psát. Potřebujeme dva programy - server a klienta.

Činnost serveru spočívá v naslouchání na daném portu. V okamžiku, kdy se na tento port přípojí klient, mohou oba programy vzájemně komunikovat. Komunikace bude probíhat následovně: Server obdrží zprávu od klienta a pošle mu odpověď. A to se bude opakovat donekonečna.

Server

Začneme tedy serverem. Nejprve vytvoříme socket pomocí metody new, jejíž parametry jsou patrné z následujícího zdrojového kódu.

use IO::Socket;

my $port = 7777;
my $ip = "192.168.0.10";

my $server = IO::Socket::INET->new(
    Proto     => "tcp",
    LocalPort => $port,
    LocalAddr => $ip,
    Listen    => 1,
    Reuse     => 1
) or die "Chyba pri vytvareni serveru! $!";

Právě jsme vytvořili socket server na ip adrese 192.168.0.10, který bude naslouchat na portu 7777. Port musíme zvolit tak, aby ho nepoužívalo více aplikací, jinak dojde ke konfliktům. Parametrem Listen určujeme nejvyšší možný počet klientů. Reuse zajistí, že po ukončení programu bez uzavření socketu se port opět uvolní.

Teď přichází chvíle pro naslouchání. Budeme naslouchat tak dlouho, dokud se nepřipojí nějaký klient. Naslouchání se provádí metodou accept, jež vrací socket, kterým lze komunikovat s klientem.

$klient = $server->accept();

Ve skalárním kontextu metoda accept vrací nový socket, ale pokud bychom přiřazovali do pole, druhým prvkem by byla ip adresa klienta.

Nyní přichází na řadu samotná komunikace s klienty. Směr komunikace si určuje samotná aplikace. Proto může dojít k případům, kdy oba programy spojené socketem čtou nebo zapisují do kanálu zároveň, což způsobuje uváznutí. To by se ve správně napsané aplikaci nemělo nikdy stát.

Vytvoříme tedy cyklus, uvnitř kterého budeme nejprve očekávat nějakou zprávu od klienta a následně pošleme odpověď. Se socketem pracujeme stejně jako s ovladačem.

V této souvislosti je dobré poznamenat, že by odesílaná data měli vždy končit znakem nového řádku, případně jiným znakem, který jeho funkci zastupuje.

while (1){
    $prichozi = <$klient>;
    print "PRIJATO: $prichozi";
    print "Zadej text, ktery chces odeslat: ";
    $odchozi = <STDIN>;
    print $klient $odchozi;
}

Klient

Vytvoření klienta, jak bude za chvilku patrné, je podobné.

use IO::Socket;

my $port = 7777;
my $ip_serveru = "192.168.0.10";

my $vzdaleny = IO::Socket::INET->new(
    Proto    => "tcp",
    PeerAddr => $ip_serveru,
    PeerPort => $port
) or die "Nelze spojit! $!";

Tato část klienta má za úkol zjistit, zda na portu 7777 počítače 192.168.0.10 naslouchá nějaký server a pokud tam skutečně naslouchá, připojit se k němu. Pokud ne, program se jednoduše ukončí.

Dále následuje už komunikace, která je až na směr stejná jako u serveru. První akce serveru bylo přijetí zprávy. Proto klient nejprve data odešle a poté bude očekávat odpověď.

while (1){
    print "Zadej text, ktery chces odeslat: ";
    $odchozi = <STDIN>;
    print $vzdaleny $odchozi;
    $prichozi = <$vzdaleny>;
    print "PRIJATO: $prichozi";
}

Na závěr by běžný klient ukončil spojení. Ten náš ovšem běží nekonečně dlouho (nedostane se za cyklus), takže následující řádek ve zdrojovém kódu nepoužijeme.

close $vzdaleny;

Výsledky

Zkuste si též změnit směr jednoho z programů - například, aby oba nejdříve posílaly data. Program uvázne, neboť oba data vysílají, ale nikdo je nepřijímá.

Nyní jsme hotovi a můžeme zkoušet. Zdrojové kódy klienta i serveru si můžete stáhnout. Zkusíte-li nyní na počítači 192.168.0.15 spustit server a na jiném počítači klienta, měl by náš chat fungovat. V okamžiku, kdy spouštíte klienta, musí pochopitelně již běžet server.

Pokud to z nějakého důvodu nejde, testování je v mnoha případech dobré začít přepsáním jména počítače na localhost a spustit server i klienta na tomtéž počítači. Zkuste se též podívat, zda komunikaci nebrání firewall.

Spušten server a následně klient *** Klient poslal zprávu na server *** Server odpověděl

Další možnosti

Se sockety lze mnoha způsoby experimentovat. Za vyzkoušení stojí připojení se na HTTP port 80. Napišme si zde jednoduchý skript, který vypíše systém, na kterém běží server. Tedy odešleme HTTP požadavek na nějakého vzdáleného hostitele a budeme čekat odpověď.

use IO::Socket;
use strict;

my $host = $ARGV[0];
my $sock = new IO::Socket::INET(
    PeerAddr => $host,
    PeerPort => 80,
    Proto    => "tcp"
) or die "Nelze vytvorit socket: $!";

print $sock "GET / HTTP/1.0\n\n";

while (<$sock>) {
    if (/^Server: *(.*)/) {
        print "$1\n";
        last;
    }
}

Program přijímá jako argument hostitelský server.

$ ./server.pl 127.0.0.1
Apache/2.2.4 (Unix) mod_perl/2.0.2 Perl/v5.8.7
$ ./server.pl www.linuxsoft.cz
Apache/2.2.3 (Debian) DAV/2 SVN/1.4.2 PHP/4.4.4-8+etch6 mod_ssl/2.2.3
OpenSSL/0.9.8c
$

Lokální sockety

V Unixu existuje speciální typ souborů, které jsou nazývány sockety. Právě ty nyní budeme vytvářet.

Jako ukázku si vytvoříme jednorázový server, který se pro jednoduchost ukončí hned po vyřízení prvního požadavku (vynecháme tedy cyklus).

use IO::Socket;

my $server = IO::Socket::UNIX->new(
    Local  => "/tmp/sock",
    Listen => 1
) or die "Chyba pri vytvareni serveru! $!";

my $klient = $server->accept();
my $prichozi = <$klient>;
chomp $prichozi;
print $klient ($prichozi=~/^\d{3}$/ ? "OK\n" : "CHYBA\n");

Server zkoumá, zda obdržel trojmístné číslo. Klient bude vypadat takto:

use IO::Socket;

my $vzdaleny = IO::Socket::UNIX->new(
    Peer => "/tmp/sock"
) or die "Nelze spojit! $!";

print "Zadej text, ktery chces odeslat: ";
my $odchozi = <STDIN>;
print $vzdaleny $odchozi;
my $prichozi = <$vzdaleny>;
print "PRIJATO: $prichozi";

Vytvořili jsme socket /tmp/sock, skrz který probíhá veškerá komunikace. Práce s unix sockety je prakticky stejná jako s síťovými sockety. Pro programátora se tyto dva typy liší pouze vznikem.

Verze pro tisk

pridej.cz

 

DISKUZE

Nejsou žádné diskuzní příspěvky u dané položky.



Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

16.4.2014 7:11 /MaReK Olšavský
Pro uživatele čekající na novou řadu vlajkové lodi Red Hatu bude příjemnou novinkou vydání RC RHELu 7. Jeho ambice pro nasazení i na nejnáročnější místa naznačuje výchozé systém XFS s podporou až 500 TB úložiště, podpora Dockeru, nebo (opět) lepší podpora interoperability s MS Windows. Trochu v pozadí příprav nového RHELu pravděpodobně zůstane spuštění OpenShift Marketplace.
Přidat komentář

16.4.2014 7:11 /MaReK Olšavský
Několik postojů k Post-XP éře, kdy může GNU/Linux převzít významnou část trhu, shrnula Katherine Noyes. Od „nefunguje to“ až po „funguje mnohem lépe“. Bohužel GNU/Linux není ve všech případech možnou náhradou.
Přidat komentář

15.4.2014 7:32 /MaReK Olšavský
Vývojáři Linux Mintu vydali Cinnamon 2.2, vlastní desktop (který byl ještě nedávnou „pouhou“ nadstavbou GNOME3) nabízející vše dobré z GNOME2. Pro Mint Linux a Ubuntu už v repozitářích je, do ostatních distribucí se postupně dostane. Vedle příjemného oznámení dnes stojí i finanční problémy GNOME Foundation, za něž pravděpodobně může pozitivně diskriminační program OPW, jež znamenají financování jen nezbytně nutných činností spjatých s vývojem GNOME a GTK.
Přidat komentář

15.4.2014 7:32 /MaReK Olšavský
Na blogu The Linux Rain vyšel článeček s 5 důvody „proč je podpora Linuxu od GOG.com dobrou zprávou“. Nové tituly budou, v rámci možností, vycházet na Valve, ale existuje spousta kvalitních titulů, leč se starším datem vydání.
Přidat komentář

15.4.2014 7:32 /MaReK Olšavský
Linksys, nyní již ve vlastnictví Belkinu, připravil nový router s dobrou výbavou a svobodným formwarem WRT.
Přidat komentář

11.4.2014 12:41 /MaReK Olšavský
Projekt svobodného laptopu Novena uspěl a už se sériově vyrábí, byť pro leckoho může být překážkou poměrně vysoká cena cca US$ 2000. Na webu VentureBeat si můžete přečíst rozhovor s Andrewem „Bunnie“ Huangem o důvodech konstrukce svobodného laptopu. Pořídí si jej Richard M. Stallman?
Přidat komentář

11.4.2014 12:41 /MaReK Olšavský
OT: Pro mnoho uživatelů je velmi těžké loučení s Windows XP, ale byly kritizovány možná ještě více, než aktuální Windows 8. Je důvod litovat?
Přidat komentář

10.4.2014 7:02 /MaReK Olšavský
Firma ARM, jež vyvíjí a licencuje stejnojmenou mikroprocesorovou architekturu dalším výrobcům, poskytuje i vlastní vývojové nástroje. Zajisté i k nelibosti zastánců GPL se postupně přesouvá k LLVM, od zcela vlastního překladače. LLVM je mnohem modulárnější a flexibilnější, leč s trochu problematickým licencováním.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

7.4.2014 6:31 / MaReK Olšavský
Re: No, nevím

4.4.2014 10:22 / Petr Ježek
No, nevím

4.4.2014 10:18 / Petr Ježek
ATI

24.3.2014 13:54 / Michal Linha
Re: Delimiter

24.3.2014 13:46 / Michal Linha
Re: Delimiter

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2014) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze | zákony online