Vtičnice (sockets)


Uvod

Vtičnice (sockets) omogočajo medprocesno komunikacijo (interprocess communication , IPC). Vzpostavljanje zveze z vtičnicami in sam potek komunikacije je precej analogen vzpostavljanju in poteku telefonskega pogovora.

Najprej moramo predvideti mehanizem, ki komunikacijo omogoča. To doseµemo s stavkom socket().

Glede naslavljanja vtičnic poznamo pri UNIX več načinov. Najbolj znana sta  AF_UNIX in AF_INET. AF_UNIX  identificira vtičnice z uporabo poti (pathnames). To obliko uporabljamo predvsem pri medprocesni komunikaciji na istem računalniku.  AF_INET pa predvideva uporabo Internetskih naslovov, ki jih predstavljamo  v znani obliki ±tirih ±tevilk, ločenih s pikami  (na primer 192.9.200.10). Poleg naslova računalnika moramo navesti ±tevilko vrat (port number), kar omogoča uporabo več vtičnic na enem računalniku.
Navesti moramo ±e tip vtičnice. Nabolj pogosta tipa sta SOCK_STREAM in  SOCK_DGRAM. SOCK_STREAM predvideva prenos podatkov v obliki znakovnih nizov.  SOCK_DGRAM nakazuje prenos podatkov v obliki datagramov. Laµja in bolj popularna je prva oblika vtičnic.
Naslednji korak je, da vtičnici damo nek naslov. To doseµemo s funkcijo bind( ) .
Vtičnice tipa SOCK_STREAM  omogočajo uvr±čanje prihajajočih zahtevkov za povezavo, kar je nekako analogno telefonskemu čakanju na klic ("call waiting"). Če je "linija zasedena", pač čakamo, da se sprosti. To lahko doseµemo s funkcijo listen( ) ,ki sicer ni nujno potrebna.
Ko smo naredili vtičnico, moramo počakati na klic z uporabo funkcije  accept( ). To je analogno dvigu telefona, če ta pozvoni. Funkcijo accept uporabljamo v streµnem procesu.

Pri procesu-klijentu je stvar bolj preprosta.  S funkcijo socket( ) naredimo vtičnico in se nato s funkcijo connect( ) poveµemo z vičnico streµnega procesa.

Sam pogovor poteka s klici, ki jih poznamo za delo z datotekami. Podobno nato na koncu tudi povezavo zapremo z znanim klicem close ( ).



Medprocesno komunikacijo s pomočjo priključkov (sockets) ponazoruje naslednji primer dveh procesov (na računalniku z operacijskim sistemom UNIX). Eden od obeh deluje kot streµnik in ga poµenemo najprej (v ozadju). Drugi proces je kot klijent.


Koda streµnega procesa

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#define NSTRS 3
#define ADDRESS "mysocket"
char *strs[NSTRS] = {
   "Prvi niz poslan s streznika na klijent\n",
   "Drugi niz poslan s streznika na klijent\n",
   "Tretji niz poslan s streznika na klijent\n"
};

main() {

   char c;
   register int i, s, ns, len;
   FILE *fp;
   int fromlen;
   struct sockaddr_un saun,  fsaun;
   if ((s = socket (AF_UNIX,SOCK_STREAM, 0)) <0) exit(1);
   
   saun.sun_family = AF_UNIX;
   strcpy(saun.sun_path, ADDRESS);
   unlink(ADDRESS);
   len = sizeof(saun.sun_family) + strlen(saun.sun_path);
   if (bind(s, &saun, len) <0) exit(2);
   if (listen(s,5) <0) exit(3);
   if ((ns = accept(s, &fsaun, &fromlen)) <0 )  exit(4);

   fp = fdopen(ns,"r");
   for (i=0; i< NSTRS; i++) 
      send( ns, strs[i], strlen(strs[i]), 0);

   for (i=0; i<NSTRS; i++) {
      while ((c = fgetc(fp)) != EOF) {
         putchar(c);
         if (c== '\n') break;
      }
   }
   close (s);
   exit(0);
}

Koda klijenta

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#define NSTRS 3
#define ADDRESS "mysocket"
char *strs[NSTRS] = {
  "Prvi niz poslan s klijenta na streznik\n",
  "Drugi niz poslan s klijenta na streznik\n",
  "Tretji niz poslan s klijenta na streznik\n"
};

main() {
   char c;
   register int i, s, len;
   FILE *fp;
   struct sockaddr_un saun;

   if ((s = socket (AF_UNIX,SOCK_STREAM, 0)) <0) exit(1);
   
   saun.sun_family = AF_UNIX;
   strcpy(saun.sun_path, ADDRESS);
   len = sizeof(saun.sun_family) + strlen(saun.sun_path);
   if (connect(s, &saun, len) <0) exit(2);

 
   fp = fdopen(s,"r");
   for (i=0; i< NSTRS; i++) {
      while ((c = fgetc(fp)) != EOF) {
         putchar(c);
         if (c== '\n')  break;
      }
   }
   
   for (i=0; i< NSTRS; i++)
      send (s,strs[i], strlen(strs[i]), 0);
   close (s);
   exit(0);
}