Documente Academic
Documente Profesional
Documente Cultură
,J
LINU X
'<.
Sabin Buraga este asistent universitar la Facultatea de Informatic, Universitatea Al.I. Cuza".
Dintre domeniile sale de interes se enumer tehnologiile Web, reelele de calculatoare i sistemele
de operare.
Gabriel Ciobanu este
Romn, filiala lai.
cercettor
principal I la Institutul de
Informatic Teoretic,
http: //www.polirom.ro
Editura POLIROM
Iai, B-dul Copou nr. 4, P.O. BOX 266, 6600
Bucureti, B-dul l.C. Brtianu nr. 6, et. 7
Naionale:
BURAGA, SABIN
Atelier de programare n refele de calculatoare I Sabin Buraga, Gabriel Ciobanu
Iai, Polirom, 2001
240 p.; 24 cm
ISBN:
973-6~3-755-6
I. Ciobanu, Gabriel
Printed in ROMANIA
Academia
B.~~~~~~ASI
Dedicat
din
crfile
Cupri ns
Mulumiri
Prefa
11
Introducere
1.1 UNIX i Linux
1.2 Comenzi uzuale
1.2.1 Exerciii
1.2.2 Rezolvri
13
13
13
13
14
Gestiunea fiierelor
2.1 Prelucrarea fiierelor
2.1.1 Primitiva open()
2.1.2 Primitiva read()
2.1.3 Primitiva wri te O
2.1.4 Primitiva lseek()
2.1.5 Primitiva close O
2.1.6 Exemplu . . . . . .
2.2 Prelucrarea atributelor fiierelor .
2.2.1 Exemplu . . . . . . . . .
2.3 Prelucrarea directoarelor . . . . .
2.4 Prelucrarea fiierelor de sistem
2.4.l Gestiunea conturilor de utilizatori
2A.2 Gestiunea grupurilor de utilizatori
2.4.3 Gestiunea sesiunilor de lucru
2.5 Exerciii .
2.6 Rezolvri
31
31
32
33
33
33
34
34
37
39
41
42
42
43
44
46
Procese
3.1 Noiuni fundamentale
3.2 Comenzi pentru procese
47
54
54
56
5
3.3
3.4
3.5
3.6
58
62
64
64
, 4 ) Semnale
4.1 Prezentare general . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 Manipularea semnalelor . . . . . . . . . . . . . . . . . . . . . .
4.2.1 Definirea unui anumit comportamen t la apariia unui
semnal .
. .
4.2.2 Trimiterea unui semnal unui proces .
4.2.3 Ateptarea unui semnal
. .
4.2.4 Suspendarea execuiei unui proces
4.3 Exemplu .
4.4 Alarme. . . . .
4.4.1 Exemplu .
4.5 Exerciii . . . .
69
69
71
77
93
Interfaa
7.1
7.2
7.3
socket
Preliminarii
. .
Interfaa socket
. . . .
7.2.1 Primitiva socket O .
7.2.2 Exemplu . . . . .
7.2.3 Primitiva socketpair()
7.2.4 Exemplu .
Exerciii . .
. ...
71
72
72
73
73
74
75
76
77
77
79
80
81
82
83
93
94
96
98
120
120
122
123
125
128
128
130
131
131
131
133
134
134
135
135
136
137
138
139
145
145
150
150
151
156
156
160
160
161
168
176
177
186
186
189
190
194
196
198
198
198
200
13 Biblioteca ncurses
13.1 Descriere general . . . . . . . . . . . . . .
13.2 Prezentarea funciilor bibliotecii ncurses . _.
13.3 Enunul unei probleme . . . .
13.3.1 Rezolvarea problemei .
214
214
214
217
217
14 Mediul Glade
14.1 Formularea i rezolvarea problemei . . . . . . .
14.2 Conceperea interfeei . . . . . . . . . . . . . . .
14.2.1 Utilizarea mediului de dezvoltare Clade
227
227
227
227
Bibliografie
234
Glosar
235
Mulumiri
!l
4
4
7
7
7
7
7
7
Mulumim
Prefa
'"
Autorii
iulie 2001
Iai,
Capitol ul 1
1.1
UNIX
Linux
aplicaii.
1.2
Comen zi uzuale
Reaminti m o parte dintre cele mai utilizate comenzi UNIX (Linux) prin intermediul ctorva...
1.2.1
Exerciii
2.
Exist
Dac
14
Atelier de programar e n
Precizai
3.
care este
diferena
reele
de calculatoa re
ntre:
4. Ce efect are
urmtoarea
linie de comenzi?
5. Ce anume
realizeaz
6.
7.
se
afieze toi
8.
9.
10.
cror
se compare
execuia
cient?):
celor
dou
nume se
verific
trimit
termin
fiier coninnd
cu
numele
cat I wc
(cat </dev/tty >/tmp/f
1.2.2
wc </tmp/f
Rezolvri
Introducere
stocarea
persistent
numirea
informaiilor
informaiilor,
15
(servicii de directoare),
interfaa
interfaa universal
Sistemul de
fiiere
structura
la resursele
reelei.
logic arborescent
a directoarelor,
protecia
(obinuite) coninnd
main,
16
reele
de calculat oare
I-nodu ri
n UNIX, numrul de fiiere care se pot afla la un momen t dat pe un sistem de fiiere este limitat precis, nc de la crearea sistemu lui de fiiere.
Fiecare fiier posed un i-nod ( i-node) care conine aproap e toate informaiile legate de acel fiier, except nd coninutul
i numele. Unele
i-nodur i sunt nefolosite la un momen t dat.
Cele mai multe cmpur i ale unui i-nod pot fi vizualizate cu ajutoru l
comenzii ls (despre ls vom discuta mai detaliat mai trziu n cadrul
acestui capitol) .
Coman da ls are ca argume nte nume de fiiere, nu i-noduri, dar cum
fiecare fiier are un singuri -nod, ls va cunoate de unde s ia informaiile.
Pentru a vedea ce i-nod corespu nde unui
De exemplu:
fiier
se poate da ls -i.
rdcin
urmtoare:
17
Introducere
I etc/hosts
care
s8.
conine
activeaz
lista numelor
sistemul.
mainilor
din
reeaua local
Iat
o parte dintre
1-
le
n
~-
gsete i
aplicaii
aplicaii
C;
sau de compi-
imaginea
binar
a nu-
(partiii
FAT,
/proc gzduiete sistemul virtual de fiiere proc i conine cte un subdirector pentru fiecare proces existent, plus date despre conexiunile
de reea. Acest sistem virtual de fiiere reprezint principala modalitate prin care nucleul "afl" informaii despre starea sistemului i
a proceselor.
Comenzile pentru prelucrarea directoarelor sunt:
mkdir path -
creeaz
an director
afieaz
schimb
ls [ optiuni ] [ path ] -
listeaz coninutul
unui director.
18
Atelier de programare n
Argume ntul path
slash.
O
reprezint
reele
de calculatoare
comand
Cum majorita tea comenzilor pot accepta un numr impresio nant de opcel mai bine este s consultm manualu l oferit de sistem. Acest
lucru se realizeaz prin intermed iul comenzii man. Manualu l sistem este
structur at pe seciuni, acestea fiind:
iuni,
funcii
de
bibliotec
( i. e. fprintf ());
fiierelor
speciale;
urmnd
whatis.
Vom putea utiliza ls pentru a, rezolva primul exerciiu. Dnd man ls,
constatm c pentru a vizualiza doar numele subdirec toarelor
coninute
de directoru l curent putem folosi opiunea "-d".
Alte
opiuni
-a
afieaz
-1
listeaz
-t
listeaz
cror
n format lung (permisiuni, numr de blocuri ocupate, numele propriet arului, numele grupului , lungime a n bytes, data ultimei modificri, numele fiierului);
sortat
dup
data
modificrii;
Introducere
19
.e
)-
;t
e
(infoiasi):-$ ls -1 /home/lrc
total 8
users
drwxr-xr-x
5 lrc
users
lrc
2
drwx-----proprietar
grup
alii)
sunt:
r citire (Read);
w scriere (Wri te);
execut
(eXecute).
Ele arat dac un fiier poate fi citit, modificat sau respectiv executat
(pentru fiiere de tip director, poate fi cutat) de persoana respectiv.
Ca exemplu concret
s lum
un
fiier
r-x-w---x
\_/\_/\_/
\_ restul lumii (others)
\__ grupul
(group)
\ ___ posesorul
(user)
\
\
\
avnd permisiunile:
20
Acest lucru
de calculat oare
nseamn c:
posesorul
modifica;
fiierului
poate citi
reele
fiierului
executa acest
fiier,
fiierul,
dar nu l poate
fiier, ns
nu l
acestor a este
urmtoarea:
bitul SUID (Set User ID): un fiier cu acest bit setat arat faptul
c execuia acestui fiier d natere unui proces care
are proprie tar
pe posesorul fiierului, i nu pe posesorul procesului care execut
fiierul (vezi i capitolu l 3). Un bit SUID setat este indicat
de comanda ls -1 printr-u n "s" n loc de "x":
(infoia si):-$ ls -1 /usr/bi n/chfn
-rws--x --x 1 root root 13184 Aug 31
similar, acionnd
asupra
Aceti
fiiere
urmtoarea semantic:
la fiiere executabile iniial acest bit indica nucleului s optimizeze folosirea fiierului: odat executa t (deci citit n memorie) va fi pstrat n memorie, chiar dac procesul se termin,
pentru c probab il va fi reapela t din nou, n curnd.
pentru directo are indic faptul c n directoarele n care oricine
poate scrie ( e.g. /tmp), teoretic oricine poate terge orice fiier.
Un bit lipicios pe un astfel de director va permite ns tergerea
unui fiier doar de ctre proprie tarul lui.
21
Introducere
Dac
I Categorie I
User
Group
Others
400
40
4
200
20
2
100
10
1
Atelier de programare n
22
reele
de calculatoare
9 16:34 program .c
9 16:34 program .c
2. Putem trece astfel la rezolvarea celui de-al doilea exerciiu. Pentru aceasta,
vom reaminti cele mai populare comenzi de lucru cu fiierele:
cp file1 file2 - copie
fiiere;
tar (mai multe nume de fiiere pot desemna acelai fiier; legturile
pot fi hard (se creeaz i o copie a coninutului fiierului) sau soft
(legtura simbolic va conine doar numele ctre fiierul surs);
exist
o serie de
opiuni
folositoare:
Introducere
23
fiiere;
more file (s) - afieaz paginat coninutul fiierelor (se iese cu : q);
less file (s) - similar cu more, dar permite parcurgerea
a,
fiierului
n ambele sensuri (un ecran n sus cu "p", un ecran mai jos cu spaiu,
cutarea unui ir cu "/");
tac file (s) - analog cu comanda cat, dar afieaz de la sfrit
ctre
nceput
wc file(s) -
e
r.i
fiierul;
afieaz numrul
fiier:
(infoiasi):-/tmp$ wc list_users
143
1218
8096 users_list
etc.):
(infoiasi):-/tmp$ file*
datafiles:
gaend:
"
directory
ELF 32-bit LSB executable,
Intel 80386, version 1
go:
ASCII text
helpfiles:
directory
directory
hintfiles:
lastgaen.zip: Zip archive data, at least v1.0 to extract
mailspool:
directory
motd1:
AS,CII text
sabeav.zip:
Zip archive data, at least v2.0 trr extract
syslog.corn:
English text
syslog.link: ASCII text
userfiles:
directory
users_list:
ASCII text
(infoiasi):/dev$ file tty
tty:
character special
24
Atelier de programare n
afieaz
reele
diverse
de calculatoare
informaii
despre
fiiere:
>
fiier
tastatur
specificat).
redirecteaz ieirea
ntr-un
fiier
adugate
la
ist).
ieirea
ex-
soluia
la
exerciiul
propus:
fiierului
cu numele file,
dac
form
dac exist
fiierului
cu numele cat,
complicat:
echo ' who I cut -c1-9 I sort I uniq ' >> users
25
Introducere
Pentru a putea rezolva acest
comenzi folositoare:
exerciiu, s enumerm nc
o serie de
decupeaz
:l
poziiile
10 vom
s lynx
s
s
s
s
s
alta
g='t
dir=
p=pi
a='t
comand
pstreaz
dintr-un
fiier
alabil ordonate.
acestea, dm cteva comenzi referitoare la utilizatori
UNIX este un sistem multi-utilizator):
Dup
c
(s
nu
uitm
26
afind
S ncercm s rezolvm
list generat.
Dup
cum se observ, puterea shell-ului rezid n abilitatea de a prelucra, ntr-un mod nlnuit, mai multe comenzi, folosind substituia prin
intermedi ul apostroafelor grave.
5. Pentru a rezolva acest exerciiu s ne reamintim cum sunt
utilizatori i n cadrul unui sistem UNIX.
gestionai
Introducere
:1
27
De asemenea, fiecare utilizator poate aparine mcar unui grup de utilizatori. Grupul este identificat de identificatorul de grup GID. UID-ul i
GID-ul se gsesc n fiierul /etc/passw d n care pentru orice utilizator
se memoreaz pe o linie:
numele contului su (login name),
parola (din considerente de securitate, de cele mai multe ori parolele
sunt "umbrite", fiind nregistrate n alt fiier, inaccesibil pentru utilizatorii obinuii, denumit /etc/shado w),
UID-ul (O dac acel utilizator are drepturi depline), corespunznd
utilizatorului special root,
GID-ul (O dac acel utilizator are drepturi depline), corespunznd
grupului special root,
alte informaii (nume real, an de studii, telefon etc.),
directorul personal al utilizatorului (home),
interpretoru l de comenzi (shell-ul) folosit (e.g. /bin/bash) .
Fiecare dintre aceste cmpuri va fi delimitat de caracterul ": ".
Un fragment dintr-un fiier /etc/passw d poate fi (parola nu apare, ea
fiind substituit de un "x"):
busaco:x:5 00:500:Sab in-Corneliu Buraga:/ho me/busaco: /bin/bash
Aadar,
linia de comenzi
28
Atelier de programare n
O
reele
de calculatoare
este:
desemneaz
apariie
a unui element
* opera tor care desemneaz zero, una sau mai multe apariii.
+ opera tor care
desemneaz
specific
desemneaz
exact n
apariii.
apariii.
alternativ.
deci urmtoarea:
urm
Introducere
29
8. Vom utiliza comanda find pentru a cuta fiiere folosind diverse criterii
i, eventual, a realiza anumite aciuni asupra lor. Cutarea se va efectua
pornind de la un anumit director care va fi explorat conform criteriilor
de cutare alese.
Sintaxa
general
a comenzii este:
se poate realiza
dup:
Ca
aciune executat
afiarea
execuia
numelui
la gsirea unui
fiier
fiierului gsit
- se
putem avea:
folosete opiunea
-print;
unei comenzi - se utilizeaz opiunea -exec. irul de caractere "{}" va &ubstitui numele fiierului gsit i ~ putea fi dat
ca argument al comenzii care va fi executat. Vom sfri lista argumentelor pasate comenzii cu caracterul punct-virgul.
Atelier de programare n
30
reele
de calculatoare
11 { } 11 " ; "
dou
Capitolul 2
Gestiunea
fiierelor
2.1
Dup
Prelucrarea
cum am
vzut
fiierelor
trateaz
manier unitar~ierele.
Programatorul poate astfel gestiona att fiierele propriu-zise, ct i dispozitivele periferice sau alte abstraciuni prin intermediul aceleiai interfee.
Astfel, avem la dispoziie dou moduri de prelucrare a fiierelor:
prin intermediul descriptorilor - fiecrui fiier i se va asocia un ntreg
denumit handler, iar operaiile asupra fiierului se vor realiza apelnd
diferite primitive puse la dispoziie de nucleul sistemului de operare;
prin intermediul structurii FILE definite n stdio. h, operaiile asupra
fiierelor realizndu-se prin apelarea funciilor din biblioteca standard de
intrare/ ieire.
De reinut faptul c folosind prima modalitate recurgem la apelurile (primitivele) sistem (prelucrare low-level ), iar n al doilea caz fiecare operaie
de intrare sau de ieire se realizeaz prin intermediul funciilor de bibliotec,
utilizndu-se un buffer intern. n implementarea lor intim, funciile de bibliotec se vor baza pe primitivele puse la dispoziie de nucleul sistemului.
Tabelul 2.1 sintetizeaz principalele operaii care se pot efectua asupra
fiierelor.
32
Atelier de programar e n
Tabela 2.1:
Operaie
2.1.1
Operaii
de calculatoa re
asupra
fiierelor
deschidere
citire
open()
read()
scriere
writeO
poziionare
lseek()
nchidere
reele
fopen()
freadO
fgetc()
fgetsO
fscanf()
fwriteO
fputcO
fputsO
fprintf( )
fseek()
ftell()
fclose()
close()
Primitiv a open()
urmtorul
prototip:
adugare
fiierului, dac
scriere;
el nu
la
sfrit;
exist
deja;
fi
a
o
Gestiunea
fiierelor
O_EXCL - utilizar e
fiierul exist
O_ TRUNC -
"exclusiv" a fiierului:
deja, se va returna eroare;
33
dac
lui este
ters;
Parame trul mode se folosete numai dac fiierul este creat i specific drepturile de acces.
Pentru crearea fiierelor poate fi folosit i primiti va creat( ) echivalent
cu specificarea opiunilor O_WRONLY I O_CREAT I O_TRUNC la open() .
2.1.2
Primi tiva re ad O
fiier
deschis se
realizeaz
cu apelul re ad():
2.1.3
Scrierea datelor se
realizeaz
cu wri te():
2.1.4
Operaiile
fiier
34
reele
de calculato are
Se
ztor
dac
dac
dac
fiierul
poziionarea
corespun-
se face relativ
poziionarea
poziionarea
se
se face
realizeaz
Paramet rul offset poate lua i valori negative, reprezen tnd deplasamentul, calculat n octei.
n caz de eroare, se returneaz -1, altfel noua poziie n fiier, relativ la
nceputu l acestuia.
2.1.5
posibilit atea ca descriptorul de fiier s fie din nou disponibil pentru utilizare, nchiznd descriptorul. La terminar ea unui proces, toate
fiierele deschise sunt nchise automat .
Apelul close () are forma urmtoare:
Aceast primitiv d
2.1.6
Exemp lu
Gestiunea
Codul
surs
fiierelor
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define NL
10
#define MAXLINE 4096
:e
int
main (int argc, char argv[])
:a
:i-
la
char c;
char s = (char) malloc (MAXLINE * sizeof (char));
/ 1 daca am term~at parcurgerea fisierului */
int gata = O;
I pozitia in cadrul fisierului */
int pos = -1;
I fisierul de intrare /
FILE fi;
te
= fopen
(argv[1], "rt"))
==
NULL)
un
cu
35
Atelier de programare n
36
reele
de calculatoare
-1);
Paii importani
sunt
pe care trebuie
s-i urmm
urmtorii:
Il
Gestiun ea
fiierelor
37
Uneori, la compil area unor funcii care vor fi incluse ulterior n cadrul
unei biblioteci va trebui generat numai codul obiect, fr a se iniia i
procesul de editare de legturi. Pentru aceasta, vom utiliza opiunea -c,
rezult nd un fiier obiect cu extensi a . o, i nu un program executabil.
Dac program ele noastre vor necesita funcii de bibliote
c al cror cod
nu este inclus n cadrul bibliotecilor de sistem standar d, atunci va trebui
s specificm numele bibliotecii care va fi folosit n
momen tul editrii
de legturi. Acest lucru se realizeaz apelnd la opiunea -1 urmat de
numele bibliotecii:
gcc gaen.c
-o~aend
-lcryp t
Putem specifica de asemeni calea ctre fiierele de bibliotec prin opiunea -L sau calea spre fiierele antet care vor fi
utilizat e apelnd la
opiunea -I.
Pentru optimiz area codului se va folosi opiunea -0, iar pentru controlul
avertism entelor furniza te de compil ator se va utiliza -W.
ul
Mai multe
se
e,
se
./mytac
o,m
Dac
au aprut erori de execuie, va trebui s reeditm i apoi s recomprogramul. Pentru depana rea avansat a programelor noastre ne
putem sluji de utilitare le gdb, strace sau ltrace .
pilm
~x-
de
le)Si
amnunte
2.2
fiierelor
n afara posibilitii de a realiza operaii asupra coninutului fiierelor, programatoru lui i se pune la dispoziie o serie de apeluri de sistem pentru a consult
a
Atelier de programare n
38
de calculatoare
reele
~--~~~
~~~~~~
ve
modifica diverse proprieti Sal~ atribut e ale fiierelor. Aceste primiti
iar detaliile
de sistem n mod uzual sunt definite n fiierul antet unistd . h,
pentru
(astfel,
sistem
de
lului
explicative se pot regsi n seciunea 2 a manua
.
a afla amnunte privito are la chmod () vom utiliza man 2 chmod)
Se pun la dispoziie urmtoarele primiti ve pentru :
i/sau
legturi
hard: link() ,
asocierea unei
legturi
de leg
furniza rea informaiilor despre atribu te (tip, permisiuni, numr
i acultime
timpul
a,
mrime
i,
turi hard, UID-ul i GID-u l propri etarulu
cesri, modificri etc.): stat() .
i
structur
crei definiie
este
urmtoarea
(vezi
struct stat
{
st_dev ;
dev_t
st_ino ;
ino_t
st_mod e;
t
mode_
st_nli nk;
nlink_ t
st_uid ;
uid_t
st_gid ;
gid_t
st_rde v;
dev_t
st_siz e;
off_t
unsign ed long st_blk size;
unsign ed long st_blo cks;
st_atim e;
time_t
st_mti me;
time_t
st_ctim e;
time_t
};
/* device */
/* inod */
I* permis iuni */
/* numar de leg. hard *I
/* UID propr ietar */
/* GID propr ietar */
/* tip device
/* marime (in octeti ) */
I* lung. blocul ui pt. I/O */
/* numaru l de blocu ri alocat e */
/* timpul ultimu lui acces */
I* timpul ultime i modif icari */
/* timpul ultime i schimb ari a starii *I
Gestiune a fiierelor
2
2.2.1
Exemp lu
#includ e
#includ e
#includ e
#includ e
#includ e
<sys/st at.h>
<sys/typ es.h>
<unistd .h>
<pwd.h>
<stdio.h >
li
):
c-
:zi
if (stat (filenam e, &st_str )
{
==
-1)
printf ("bloc" );
isdev = 1;
}
*I
39
else
if ((st_str .st_mod e & S_IFMT)
{
==
S_IFCHR)
s furnizm
40
isdev
reele
de calculatoare
= 1;
el se
S_IFREG)
S_IFIFO)
Gestiunea fiierelor
41
2.3
Prelucrarea directoarelor
fiierul
struct dirent
{
long d_ino;
unsigned short d_reclen;
char d_name [NAME_MAX+1];
f * numar i-nodului */
f * lungime d_name */
/* nume intrare (terminat cu '\0') */
afia
DIR
*dp;
struct dirent *dirp;
if (argc != 2)
toate
intrrile
dintr-un anumit
Atelier de programare n
42
reele
de calculatoare
la
dispoziie i funciile
chdir O
schimb
mkdir ()
creeaz
rmdir O
terge
getcwd()
2.4
directorul curent;
un director;
un director gol;
furnizeaz
Prelucrarea
directorul curent.
fiierelor
de sistem
2.4.1
n capitolul 1, /etc/passwd este un fiier vital al sistemului, coninnd informaii despre utilizatorii care au conturi pe acea main.
Pentru a putea prelucra informaiile din acest fiier, vom recurge la funciile
definite n antetul pwd. h:
Dup
cte am
vzut
dac
cunoatem
Gestiunea
fiierelor
43
struct passwd {
char
*pw_name;
char
*pw_passwd;
uid_t
pw_uid;
gid_t
pw_gid;
char
*pw_gecos;
char
*pw_dir;
char
*pw_shell;
definit
astfel:
/* numele utilizatorulu i */
/* parola */
I* UID */
/* GID */
/* numele real */
I* directorul 'home' */
/* shell-ul utilizat */
};
Funcia
/* inchidem f isierul */
endpwent ();
return (pw_str);
e
}
ll
2.4.2
Atelier de programare n
44
Structura ncapsulnd
struct group {
*gr_name;
char
*gr_passwd;
char
gr_gid;
gid_t
**gr_mem;
char
informaiile
I*
I*
I*
I*
reele
de calculatoare
numele grupului */
parola grupului */
GID */
membrii grupului */
};
2.4.3
/*
/*
/*
/*
/*
/*
/*
/*
tipul de login */
PID-ul procesului login */
numele terminalului fara "/dev/" */
numele utilizatorului */
numele hostului de conectare */
identificatorul sesiunii */
timpul de conectare */
adresa IP a hostului */
};
Vom utiliza aceast structur pentru a parcurge unul dintre cele dou fiiere
de mai sus. Astfel, vom putea implementa funcia de mai jos care simuleaz
comportamentul comenzii who (datele nu vor fi afiate la ieirea standard, ci
vor fi memorate ntr-un fiier):
/* genereaza un fisier care va contine informatii despre
sesiunile utilizatorilor curenti din sistem */
int
who (char *utmpfilename, char *whofilename)
{
Gestiunea
fiierelor
45
int idle;
char *ptr_date, idle_str[6], utty[80];
/* deschidem f isierul utmp */
if ( (infp = fopen (utmpfilename,
r 11 ) )
NULL)
NULL)
11
fclose (infp);
return -2; /* eroare */
:1
)
;i
Atelier de programare n
46
reele
de calculatoare
}
}
2. 5
i
Exerciii
exerciii
spre rezolvare:
sfritul
unui
fiier coni
1.
2.
3.
4.
5.
6.
7.
adauge la
implementeaz
simuleaz
comanda tail.
comanda grep.
opiuni
afia
meniuri
Fiecare dintre
fiierele
urmtor:
Gestiunea
2.6
Exerciiul
exerciiile
propuse
rezolvrile
acestora.
i-
47
Rezolvri
fiierelor
urmtoarea
- am utilizat
<sys/types .h>
<sys/stat.h >
<unistd.h>
<fcntl.h>
<stdio.h>
int
main (int argc, char **argv)
{
lri
or
:3,
:le
um
}
/* deschidem al doilea f isier pentru scriere (cu adaugare) */
if ((out = open (argv[2], O_WRONLY I O_APPEND)) < O)
{
perror (argv[2]);
exit (1);
}
48
reele
de calculato are
/* inchidem f isierele */
clase (out);
clase (in);
exit (O);
}
Urmtorul
5. Implem entarea
program
opiunilor
implementeaz opiunile
comenz ii ls
'-1', '-a'
time_t f_mtime;
struct dirent *file;
};
Gestiunea
fiierelor
int R, i;
if (Infos.st_mode & S_IFDIR)
printf ("d");
el se
printf ("-");
for (i = O; i < 3; i++)
{
int P = 1, j;
for (j =O; j < (2 - i); j++) /* calculeaza s-(2-i) */
p
*=
8;
* P;
if (Infos.st_mode & R)
printf ("r");
el se
printf ("- ");
R /= 2;
if (Infos. s.t_mode & R)
printf ("w");
el se
printf ( "-") ;
R /= 2;
if (Infos. st_mode & R)
printf ("x");
el se
printf ("- ");
R = Ox04
}
}
49
Atelier de programare n
50
reele
de calculatoare
struct tm *timp;
timp= localtime (&Infos.st_mtime) ;
printf (" %s %2d", Months[timp->tm_m on], timp->tm_mday);
printf (" %2d:%2d", timp->tm_hour, timp->tm_min);
}
/* programul principal */
int
main (int argc, char *argv[])
{
O, All
O)
O;
i
I
Gestiunea
printf
printf
printf
printf
return
("Usage:
("
("
("
fiierelor
O;
continue;
}
}
li
li
- '
1)
!= O)
if ((Fisiere[i] =
(struct Files *) malloc (sizeof (struct Files))} ==
NULL)
{
if (CurrentDir == 1)
strcpy (FileName, namelist[i]->d_name);
51
52
Atelier de programare n
reele
de calculatoare
el se
sprintf (FileName, "%s%s", Dir, namelist[i]->d_name);
if (stat (FileName, &Infos) == -1)
{
Fisiere[i]->f_mtime = Infos.st_mtime;
Fisiere[i]->file = namelist[i];
}
if (n < O)
{
if (Time
==
1)
inti,j;
struct Files *Aux;
for (i =O; i < (n - 1); i++)
for (j = i + 1; j < n; j ++)
if (Fisiere[i]->f_mtime > Fisiere[j]->f_mtime)
{
Aux = Fisiere[i];
Fisiere[i] = Fisiere[j];
Fisiere[j] = Aux;
}
}
O; i < n; i++)
for (i
{
==
if (All
O)
'
== ". ")
if (CurrentDir == 1)
strcpy (FileName, Fisiere[i]->file->d_name);
el se
sprintf (FileName, "%s%s", Dir, Fisiere[i]->file->d_name);
if (List == 1)
{
== -1)
Gestiunea
fiierelor
return 2;
}
Rights ();
printf (" %3d", Infos.st_nlin k);
OwnerName O ;
OwnerGroup ();
printf (" %7d", Infos.st_size );
Date O;
printf (" %s\n", Fisiere[i]->fi le->d_name) ;
}
printf ("\n");
return O;
}
53
Capitolul 3
Proc ese
Acest capitol prezint noiunile fundamental e referitoare
la procese i modalitile de gestiune a proceselor.
Noiuni
3.1
fundam entale
Un program (cod binar) devine proces atunci cnd este apelat pentru rulare.
Procesul, aadar, reprezint imaginea dinamic a unui program aflat n execuie. Pentru un program pot exista la un moment dat mai multe procese asociate
pe care le vom numi instane ale acelui program.
n UNIX (i n particular n Linux) fiecare proces va avea asociate mai
multe atribute, cele mai importante fiind:
identificat orul de proces (PID) este un ntreg mai mare dect zero; la iniializare, nucleul sistemului de operare va crea un pseudo-proc es cu PID
nul care va genera procesul init al crui PID va fi 1. Fiecare proces va
avea un printe care l-a creat, iar procesul init va putea fi considerat
strmoul tuturor proceselor existente la un moment dat n sistem. Valoarea PID-ului unui proces va fi stocat de tipul pid_ t definit n antetul
sys/types. h.
identificat orul procesulu i printe (PPID) reprezint identificatorul procesului care a creat procesul curent; dac un proces i-a pierdut printele,
n mod automat l va avea drept printe pe procesul init (deci PPID-ul
su va fi 1).
identificat orul grupului de procese -- fiecare proces poate aparine unui
grup ele procese; dac PID-ul procesului este egal cu identificatorul grupului de procese, atunci acel proces este lider al acelui grup.
terminalu l de control asociat procesului; este primul terminal deschis de liderul grupului ele procese (n cazul proceselor utilizator este terminalul la
care s-a conectat acel utilizator). Accesul la terminalul asociat se va face
prin intermediul fiierului I dev /tty 1 . Dac un proces interacioneaz cu
utilizatorul prin intermediul terminalului, atunci acel proces ruleaz n
1 La
Procese
55
execut
acel proces.
GID-ul procesul ui este GID-ul grupului din care face parte utilizator ul care
execut acel proces.
c-
e
u
i)
)-
e,
11
ui
Ll-
ela
ce
~u
n
:e.
UID-ul efectiv (EUID) coincide de cele mai multe ori cu UID-ul, servind
la determina rea dreptului de acces la resursele unui anumit proces. n
unele cazuri anumite procese2 trebuie s ruleze sub auspicii de superutilizator - root - i atunci EUID-ul acelor procese va fi egal cu UIDul utilizator ului root, adic O. Ca exemplu, cazul n care un utilizator
obinuit dorete s-i modifice informaiile de finger prin intermedi ul
comenzii chfn care va opera asupra fiierului sistem /etc/pass wd.
GID-ul efectiv (EGID) ca mai sus, pentru grupul din care face parte utilizatorul care va executa procesul.
starea n care se afl un proces: dup creare, dac s-a reuit alocarea de
memorie pentru proces, procesul este n starea ready (pregtit pentru
execuie) fiind deja introdus n coada de ateptare a planificat orului de
procese. Atunci cnd va fi planificat pentru execuie, n funcie de o
anumit prioritate , va trece n starea run (de rulare) - rularea poate fi la
nivel de nucleu sau la nivel de utilizator. Atunci cnd procesul trebuie s
atepte un evenimen t (e.g. introduce rea datelor de la terminalu l asociat)
va trece n starea wait (de ateptare). La terminare a normal (la apelul
primitivei exi t ()) procesul"va trece n starea finished. Dac un proces nu
a fost complet scos din tabela de alocare a proceselor se numete zombie.
Procesele zombie, dei apar ca existente pe main, nu dispun de nici o
resurs a sistemulu i, suprasatu rnd inutil planificat orul de procese.
valoarea nice este o component a prioritii totale pe care o va avea un
proces, putnd fi ajustat cu ajutorul comenzii nice. Prioritate a unui
proces n Linux poate lua valori de la -20 la 20. Valorile de la -1 la -20
sunt asociate proceselqr sistemului, ele neputnd fi acordate proceselor
unui utilizator obinuit. Cea mai mare prioritate a unui proces utilizator
este O.
mulimea
are la
2
execuiei
Atelier de programar e n
56
reele
de calculatoa re
Aceti
linia de comand conine argument ele pasate procesului; pot fi folosite prin
intermedi ul primelor dou argument e ale funciei main ():
main (int argc, char *argv[])
funciilor
getenv ()
setenv ().
3.2
Urmtoarele
Comanda ps afieaz informaii despre procese. Pentru a afia toate procesele existente pe un anumit sistem putem da ps aux, iar pentru a vizualiza lista
Procese
57
propriilor noastre procese (inclusiv cele din fundal) vom da ps ux. Comanda
pune la dispoziie foarte multe alte opiuni, pentru detalii consultai manualul.
Iat un exemplu de rulare a comenzii ps:
(infoiasi):/$ ps ux
USER
PID %CPU %MEM
lrc
1524 o.o 0.6
lrc
1545 0.5 1.2
lrc
1546 0.1 0.6
lrc
1570 o.o 0.2
lrc
1571 o.o 0.3
lrc
1572 0.3 0.6
lrc
1583 o.o 0.3
1284
2456
1292
576
612
1324
756
tty3
tty3
tty5
tty5
tty5
pts/4
pts/4
STAT START
s
15:30
T
15:30
15:30
s
15:31
s
15:31
s
15:31
s
15:32
R
TIME
0:00
0:00
0:00
0:00
0:00
0:00
0:00
COMMAND
-bash
pine
-bash
script
script
bash -i
ps ux
l
e
1
.,
J
Stopped
pine
top
pine
~-
Atelier de programare n
58
reele
de calculatoare
3.3
Programatorului i se pun la
dispoziie
o serie de
pri~itive
importante:
va returna de do:gl!,_ori:
o valoare pozitiv n procesul printe, desemnnd PID-ul procesUii.iI copil
tocmai creat i o valoare nul n procesul copil. n caz de eec, fork ()
returneaz -1. Procesul printe i procesul copil devin dou procese care
se vor executa n mod concurent, independent unul de cellalt, ncepnd
cu prima instruciune care urmeaz lui fork ().
Dei apelat
Primitiva fork() reprezint singura modalitate n UNIX de a crea procese noi n cadrul unui program.
Un proces va putea crea mai muli copii. Procesul copil va fi o copie a
procesului printe, dar cele dou procese nu vor partaja memoria zonelor
de date (statice sau dinamice) ori stiva.
Un exemplu simplu:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int
main (void)
{
pid_t pid;
/* creaza un proces nou */
pid = fork O;
printf ("Sunt procesul cu PID-ul %d,\n"
" iar apelul forkO a returnat valoarea %d\n",
getpid O , pid) ;
return O;
}
Procese
Un posibil rezultat
afiat
59
ar putea fi:
20000
long sum;
int
main
/* suma numerelor */
int i;
I* iterator */
sum = O;
if (fork () < O)
{
Atelier de programare n
60
reele
de calculatoare
cum am vzut mai sus, un proces care s-a terminat i pentru care
procesul printe nu a executat wai t () se numete zombie. Aadar, pentru
a nu crea procese zombie, trebuie s ateptm terminarea unui proces
copil prin utilizarea lui wai t O.
wai tpid () este un apel nrudit cu wai t O, dar mai flexibil:
pid_t waitpid(pid_t pid, int status, int options);
Se permite ateptarea unui proces copil sau aparinnd unui grup de procese (pentru amnunte consultai man waitpid). De asemenea, waitpid()
poate fi apelat fr a se bloca.
Apelurile wai t O
wai tpid O pot ajuta la sincronizarea
multor procese concurente.
Pentru a afla o serie de
la primitivele:
- getpid()
informaii
furnizeaz
PID-ul procesului
printe;
- getpgrp O furnizeaz identificatorului grupului de procese al procesului curent; o variant mai general este getpgid();
- setpgrp O seteaz identificatorul grupului de procese al procesului
curent; o variant mai general este setpgid ();
- getuid O
- getgid()
procesul;
furnizeaz
l
\
furnizeaz
- getppidO
execuiei mai
returneaz
I
I
Procese
geteui d()
procesul;
returneaz
61
seteaz
setgid O seteaz
lui curent.
Cale
directo r curent
directo r curent
PATH
PATH
directo r curent
directo r curent
I Environment
(mediu)
automa t
automa t
automa t
automa t
preciza t
preciza t
Apelur ile execXX () ajut la invocarea unui program (cod executa bil sau
script) de ctre un proces. Procesu l va fi nlocuit comple t de ctre codul
unui alt program (e.g. o comand UNIX).
Astfel, avem posibil itatea de a executa n cadrul aplicaiilor noastre alte
program e. Desigur, apelurile execXX() vor aprea n cadrul procesului copil.
Aadar, nucleul ncarc n zona de memorie noul program
i procesul
este continu at cu acest program , cruia i sunt transm ise argumentele. n
cadrul procesului nu se schimb dect programul, restul rmne nemodificat. La ncheierea execuiei programului se apeleaz primiti va sistem
exi t () , care cauzeaz termina rea procesului fiu i ieirea din starea de
ateptare a procesu lui printe.
Se pun la dispoziie 6 primitive, prezent ate n tabelul 3.1, -ale cror prototipur i sunt (pentru mai multe amnunte consultai manual ul):
#includ e <unistd .h>
'
62
I* argume ntele
... ) ;
reele
de calculat oare
... ) ;
... '
3.4
Exem plu
s realizm urmtorul
program care va
Procese
63
int
main ()
{
= fork
()) < O)
else if (pid)
/* parinte */
perror ("wait()");
}
el se
{
din PATH) */
*/
*/
*/
putut executa */
}
}
11
-1 11 , NULL);
complet
Atelier de programare n
64
3.5
1.
reele
de calculatoare
Exerciii
Explicai
efectul
urmtoarei secvene
de cod:
int i;
for ( i = O; i <= 9; i++)
fork
O;
2. Sunt dai n pointeri a fi() funcii al cror prototip este void fi (void),
cu i = 1, ... , n. S se scrie funcia forkn() care lanseaz n procese,
fiecare proces i executnd funcia fi().
se implementeze apelul execvp() cu ajutorul lui execv().
3.
4.
se scrie un program care verific dac sunt mai mult de 20 de sesiuni deschise pe sistem i n caz afirmativ trimite un e-mail cu subiectul "Atenie" la adresa sysadmfenrir. infoiasi. ro (pentru expedierea
mesajului se va putea utiliza comanda mail).
7.
3.6
Rezolvri
Exerciiul
2. Implementarea
funciei
forkn()
coninnd
Procese
65
int
forkn(vo id (* tab_func t[])(void ), int n, pid_t *tab_pid [])
{
.,
>
e
l-
}
Funcia returneaz numrul de procese copil care au putut fi create, iar
n
tabloul tab_pid [] sunt stocate PID-urile proceselor lansate.
>r
n
l.
Exerciiul
variant
Atelier de programare n
66
reele
de calculatoare
pathseq = colon + 1)
{
int
main ()
{
Procese
67
el se
fprintf (stderr, ")\n");
exit (1);
}
int
main O
I* programul principal */
if
syserr ("proc");
}
chdir ("/proc");
while ((dirp = readdir (dp)) != NULL)
{
ll
I
I
I
NULL)
syserr ("stat");
}
Atelier de programare n
68
reele
de calculatoare
/* si le afisam */
for (i = 1; i <= 4; i++)
{
t
= 1;
printf ("\n");
fflush (stdout) ;
chdir ("/proc");
}
}
} /* while */
closedir (dp);
return O;
}
Capitolul 4
Semnale
Acest capitol prezint noiunile fundamentale referitoare
la semnale i modalitile de tratare a semnalelor. De
asemenea, se prezint mecanismul de ataare de alarme
la procesele utilizatorilor prin intermediul primitivei
alarm().
4.1
Prezentare
general
Un semnal este un scurt mesaj transmis unui proces, la apariia unui anumit
eveniment (excepie). Semnalele pot fi ignorate sau redefinite de un anumit
proces, exceptnd un singur semnal. Un semnal nu furnizeaz informaii suplimentare despre acel eveniment, iar destinatarul unui semnal nu cunoate nici
mcar care a fost expeditorul acestuia.
Cauzele apariiei unui semnal pot fi grupate astfel:
~) '
ie
ia
la
.e, :
()
instruciuni
ilegale
evenimente generate de sistemul de operare ( e.g. inexistena unei primitive sistem, ncercarea de a accesa o zon de memorie nepermis, inexistena resurselor necesare etc.);
evenimente generate de procese utilizator sau de utilizatorul nsui (de
exemplu, terminarea forat a unui proces, activarea unei alarme, ntreruperi etc.).
Unele semnale vor provoca, odat cu terminarea procesului asupra cruia
au acionat, generarea unui fiier denumit core care va conine zona de memorie folosit de acel proces.
Cele mai uzuale semnale sunt urmtoarele:
SIGHUP (Hangup) - deconectarea terminalului (transmis la nchiderea sesiunii, se poate inhiba folosind comanda nohup); semnalul mai poate fi folosit
pentru a transmite daemonilor s-i rencarce fiierele de configuraie 1 ;
1 De exemplu, n loc de a restarta daemonul
httpd (serverul Web) prin comanda
/etc/init.d/httpd restart este suficient s dm killall -HUP httpd.
Atelier de programare n
70
reele
de calculatoare
apariia
combi-
execuia
unei
instruciuni
excepie
de
ilegale de
ctre
pro-
virgul mobil;
magistral;
SIGSE GV (Segmentation violation) - violare a memoriei (ncercare de accesare a unei zone de memorie nepermise);
SIGPIP E (Pipe error) - scriere ntr-un pipe cnd nu
din acel p'ipe (vezi capitolu l urmtor);
SIGAL RM (Alarm clock) seciunea 4.4);
apariia
exist
proces de citire
:~::::~(~;:;t::~e::::::t:;n~ ::::.:ar::::::::::~~:i~:: ,f
;
apariia
i
I
apariia
unei
urgene
(e.g.
recepia incorect
I
Pentru a vedea lista tuturor semnalelor acceptat e de sistemul de operare,
'
~
ct i corespondena dintre valorile simbolice i numerele asociate semnalelor,
vom utiliza comand a kill -1.
I
I
I
J
i
-
'!
Semnale
),
t
,_
.e
~-
il
~-
(infoiasi ): -$ kill -1
1) SIGHUP
2) SIGINT
5) SIGTRAP
6) SIGABRT
9) SIGKILL
10) SIGUSR1
13) SIGPIPE
14) SIGALRM
18) SIGCONT
19) SIGSTOP
22) SIGTTOU
23) SIGURG
26) SIGVTALRM
27) SIGPROF
30) SIGPWR
31) SIGSYS
34) SIGRTMIN+2 35) SIGRTMIN+3
38) SIGRTMIN+6
39) SIGRTMIN+7
42) SIGRTMIN+10 43) SIGRTMIN+11
46) SIGRTMIN+14 47) SIGRTMIN+15
50) SIGRTMAX-13 51) SIGRTMAX-12
54) SIGRTMAX-9
55) SIGRTMAX-8
58) SIGRTMAX-5
59) SIGRTMAX-4
62) SIGRTMAX-1
63) SIGRTMAX
71
obine urmtoarele:
3) SIGQUIT
7) SIGBUS
11) SIGSEGV
15) SIGTERM
20) SIGTSTP
24) SIGXCPU
28) SIGWINCH
32) SIGRTMIN
36) SIGRTMIN+4
40) SIGRTMIN+8
44) SIGRTMIN+12
48) SIGRTMAX-15
52) SIGRTMAX-11
56) SIGRTMAX-7
60) SIGRTMAX-3
4)
8)
12)
17)
21)
25)
29)
33)
37)
41)
45)
49)
53)
57)
61)
SIGILL
SIGFPE
SIGUSR2
SIGCHLD
SIGTTIN
SIGXFSZ
SIGIO
SIGRTMIN+1
SIGRTMIN+5
SIGRTMIN+9
SIGRTMIN+13
SIGRTMAX-14
SIGRTMAX-10
SIGRTMAX-6
SIGRTMAX-2
re
4.2
la
4.2.1
ir;
1r;
i
I
ui
1d
apariia
unm
Definirea unui comporta ment la apariia unui semnal se realizeaz prin intermediul primitive i signal() care are urmtorul prototip specificat n fiierul
antet signal. h:
#include <signal.h >
typedef void Sighandl er (int);
Sighandl er *signal( int signum, Sighandl er *function );
Pentru fiecare semnal desemnat de ntregul signum se asociaz o funcie
de tratare (handler) al lui. Funcia de tratare este o funcie avnd un singur argument desemnn d numrul unui semnal i care nu returneaz nimic.
Parametr ul function este un pointer la aceast funcie sau poate fi una dintre
valorile speciale:
Atelier de programare n
72
reele
de calculatoare
f
I
!
4.2.2
Pentru a trimite un semnal unui proces vom putea utiliza comenzile kill ori
killall sau apelul de sistem kill () a crui form este urmtoarea:
#include <sys/type s.h>
#include <signal.h >
int kill(pid_ t pid, int sig);
pid este pozitiv, va fi trimis semnalul sig procesului cu PID-ul specificat. Dac pid este zero, atunci semnalul va fi trimis tuturor proceselor din
grupul de procese al procesului curent, iar dac pid are valoarea -1 atunci
semnalul va fi trimis fiecrui proces din tabela de procese, exceptnd primul.
Pentru cazul cnd pid este mai mic dect -1, semnalul va fi trimis tuturor
proceselor din grupul de procese cu -pid.
n caz de eec, kill O va returna -1, iar n caz de succes va returna zero.
Un apel nrudit este rai se() care va trimite un semnal procesului curent.
Astfel, rai se (signum) este echivalent cu apelul kill (getpid () , .signum).
Dac
4.2.3
Pentru a
Ateptarea
unui semnal
atepta apariia
i returneaz
I
'
r
l
73
Semnale
- i
Suspendarea
4.2.4
execuiei
unui proces
execuia
funcia
li
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
4.3
Exemplu
Vom exemplifica utilizarea semnalelor prin scrierea unui program care captureaz semnalul SIGUSR2, la apariia acestuia afind fiierul /etc/services
prin folosirea comenzii less.
#include
#include
#include
,include
ein
<unistd.h>
<signal.h>
<errno.h>
<sys/types.h>
.ci
il.
void
sighandler (int sig)
or
o.
it.
pid_t pid;
if ((pid
!
II
!'
if ( !pid)
II
/* copil */
I'
'
I'
I
I
;
i'
I* parinte */
el se
{
if (wait(NULL) < O)
perror("wait()");
}
}
Atelier de programare n
74
reele
de calculatoare
int
main () /* programul principal */
{
perror ("signal()");
return 1;
}
(infoiasi):-$
(infoiasi):-$
(infoiasi):-$
1126 pts/2
1134 pts/3
(infoiasi):-$
ieirea
standard atunci
cc sig.c -o sig
./sig
ps x I grep sig
0:00 ./sig
S
0:00 grep sig
S
kill -USR2 1126
n afar de apelurile descrise mai sus, pentru tratarea unui grup de semnale pot fi utilizate apelurile sigprocmask(), sigactionO, sigpending() sau
sigsuspendO.
4.4
Alarme
setat
alarm
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
Semantica primitivei este urmtoarea: dup scurgerea numrului de secnnde dat ca argument va fi trimis semnalul SIGALRM procesului curent. Dac
seconds este zero, atunci nu mai este planificat nici o alarm. Apelul alarmO
va returna numrul de secunde care au mai rmas pn la activarea alarmei
sau zero dac nu exist nici o alarm planificat.
Semnale
4.4.1
75
Exemplu
:i
int status;
FILE * f;
static void
scrie O
if ((f
l-
u
}
void
alarma O
/* trateaza SIGALRM */
/* la
*I
while (1)
I*
I*
I*
{
:
alarm (TIMER);
pause O;
3i
}
}
*I
Atelier de programare n
76
int
main (void)
{
reele
de calculatoare
/* program ul princip al */
/* lansam procesu l in fundal */
case -1:
perror ("fork() ");
return -1;
I* copilul preia executi a */
case O:
alarma O;
/* parinte le se termina */
default :
sleep (1);
return O;
}
}
lansare, vom putea vedea cum din trei n trei secunde este scris un
alt numr n fiier utiliznd comand a tail -f alarm.
Dup
4.5
1.
\.
Exerciii
implementeaz
primitiv a sleep()
I
I
I
\1
Capitolul 5
5 .1
11
T'
le
t.
'
Preliminarii
5.2
Primitiva pipe()
Atelier de programare n
78
reele
de calculatoare
wri te() va scrie datele n ordinea sosirii n pipe (principiul first in,
first out - FIFO). Se blocheaz dac pipe-ul este plin, nu exist scrieri
pariale. De obicei, un pipe are o capacitate fix, destul de limitat. Singura metod de a se transmite un EDF este s .se nchid descriptorul
asociat.
read() citete datele n ordinea sosirii lor. Odat citite, datele nu pot fi
recitite sau puse la loc. Dac pipe-ul este vid, read() se va bloca n mod
uzual. Dac read() returneaz O, atunci nseamn c s-a ajuns la EOF.
el o se () pentru descriptorul de scriere (pfd [1]) nseamn nchidere, plus
trimiterea caracterului special EDF procesului care citete din pipe.
utilizeaz.
execut
citete
printele
6. procesul
printe i
le
proceseaz;
Procesul printe este procesul productor, iar procesul copil este procesul consumator. Consumatorul se va bloca pn cnd procesul productor va
trimite datele. Dac s-a umplut pipe-ul, productorul se va bloca pn cnd
procesul consumator va citi din pipe.
lr
1
t'
-I
q
I
5.2.1
Exemplu
Vom crea un proces copil care va citi dintr-un pipe un ir de caractere trimis de
procesul printe, convertind orice liter minuscul n liter majuscul. Procesul
printe va citi acest ir de la intrarea standard.
I
J.
!l
<stdio.h>
<ctype.h>
<stdlib.h>
<unistd.h>
<sys/wait.h>
1-
int
main (void) /* programul *I
L-
~1
perror ("pipe()");
exit (1);
}
if ((pid
{
I
'.
II
I
1.
II
if (pid)
/* parinte */
era
.d
79
Atelier de programare n
80
reele
de calculatoare
perror ("wait()");
exit (1);
}
exit (O);
}
el se
{
5.3
Primitiva fifo()
precizat,
asociat fiierului
81
5.3.1
Exemplu
(
I
I
l
i
'
II'
I
I
i
!
.i
ul
'
I
!
I
ni
),
#include
#include
#include
#include
#include
#include
#include
#include
apoi
<stdio.h>
<unistd.h>
<stdlib.h>
<fcntl.h>
<sys/types.h>
<sys/stat.h>
<sys/wait.h>
<string.h>
int
main (int argc, char *argv[]) /*programul*/
{
int pfd;
char mesaj[6];
pid_t pid;
/* cream fifo-ul */
if (mkfifo (argv[1], S_IFIFO I 0644) < O)
{
case -1:
/* eroare */
fprintf (stderr, "Eroare la fork(). \n");
Atelier de programare n
82
reele
de calculatoare
exit (3);
/* copil */
case O:
if ((pfd = open (argv[1], O_RDONLY)) < O)
{
I* scriem in f ifo */
write (pfd, "Salut, ce mai ziceti?", 22);
I* asteptam terminarea copilului */
if (wait (NULL) < O)
{
return,:O;
/* switch */
}
}
5.4
Exer~iii
metod
1.
Imaginai
2.
se scrie un program care trimite unui proces copil linie cu linie coni
nutul unui fiier, procesul copil numr liniile trimise i returneaz prin
telui numrul lor.
l
II
r
r
\
83
7. Un proces trimite unui prnces copil numele unui fiier i una dintre literele
"r'', "l", "w" sau "q", aleatoriu. Pentru "r" fiierul va fi ters, pentru "l"
va fi listat (afiat la ieirea standard), iar pentru "w" i se vor numra
liniile. Dac procesul copil recepioneaz caracterul "q" atunci va cauza
terminarea lui i a printelui.
8.
r
9.
'
lI
i
I
!
!
se simuleze activitatea de detectare a staiilor ntr-o reea de tip magisavnd 5 calculatoare. Fiecare staie trimite cte un mesaj de identificare (de ex. PID-ul propriu) n reea i ateapt mesajele celorlalte
staii. Cnd a gsit toate staiile, va afia PID-urile lor. Dac i citete
propriul mesaj, staia l va repune n reea.
tral
5.5
Rezolvri
Exerciiul
Una dintre
descris
Cunoatem
"nghearea"
s
.i
1
mai jos:
Atelier de programare n
84
reele
de calculatoare
#include <unistd.h>
I pipe-ul /
int pfd[2];
/ total va numara cate caractere vom scrie cu write
pana cand se va bloca pipe-ul /
int total = O;
void
gata O
{
int
main ()
{
I cream pipe-ul /
if (pipe (pfd) < O)
{
perror ("pipe()");
exit (1);
}
I setam alarma /
signal (SIGALRM, gata);
alarm (1);
I la infinit, scriem in pipe ... /
while (1)
{
perror ("write()");
exit (1);
}
total++;
}
I
II
I
I!
l
5. 33 de cifre
comunicaii bidirecionale
<signal.h>
<unistd.h>
<stdlib.h>
<stdio.h>
l
r
int s;
if (!read (p2[0], &s, sizeof (s)))
I
I
85
int
main () /* programul principal */
{
pid_t pid;
FILE *f;
int n = O,
x,
sum = O,
val;
/* numarul de cifre */
/* cifra citita */
I* suma calculata */
I* valoarea generata si transmisa pe pipe */
(duplex)
Atelier de programare n
86
reele
de calculatoare
I
f
case -i:
{
/* copil */
case O:
close (pi [i]) ;
close (p2[0]);
i f ((f = fopen (FILENAME, "a")) == NULL)
r
i
87
while (1)
I* la infinit ... */
exit (O);
}
}
primit
3
6
7
5
3
24
Exerciiul
t\ft- o
. r~
Sfi i'de
C}
(
'
8. Detectare a
staiilor
dintr-o
reea magistral
88
#includ e
#includ e
#includ e
#includ e
reele
de calculat oare
II
<stdio. h>
<unistd .h>
<sys/ty pes.h>
<signa l.h>
/*pipe -ul*/
int pfd[2] ;
I* vector ul statiil or detecta te */
int detecte d[4];
int mypid, pid, idx = O, nr;
/* statia este deja detecta ta? */
int
este (int idx, int elem)
{
int k;
for (k = O; k < idx; k++)
elem)
if (detect ed[k)
return 1;
return O;
}
int i;
printf ("Stati a cu numaru l %d a detect at statiil e: \n", eu);
fflush (stdou t);
for (i = O; i < 4; i++)
{
printf ("\n");
fflush (stdou t);
return O;
}
int
myfork O
{
case -1:
fprintf (stderr , "Eroare la fork.\n ");
Ii
f
return 2;
case O:
mypid = getpid ();
write (pfd[l], &mypid, sizeof (pid_t));
while (idx < 4)
{
i
i
'
}
}
int
main () /* programul principal */
{
int j;
if (pipe (pfd) < O)
/* creeaza pipe-ul */
/* cream statiile */
for (j = O; j < 5; j ++)
myfork O;
/* parintele */
close (pfd[1]);
close (pfd[O]);
/* asteaptam toti cop111 ... *I
while (wait (NULL) > O)
/* ... si am terminat*/
return (O);
}
89
Atelier de programare n
90
reele
de calculatoare
numarul 2299
2297 2298
numarul 2301
2297 2299
numarul 2300
2297 2299
numarul 2297
2299 2298
numarul 2298
2299 2301
Exerciiul
urmtoarea:
a detectat statiile:
a detectat statiile:
a detectat statiile:
a detectat statiile:
a detectat statiile:
9. Detectarea
staiilor
dintr-o
reea
inel
Pentru rezolvarea acestei probleme vom folosi fifo-uri, fiecare canal de comunicaie dintre o staie i cei doi vecini ai ei fiind simulat printr-un fifo.
#include
#include
#include
#include
<stdio.h>
<unistd.h>
<fcntl.h>
<sys/types.h>
#define MAX_STATII 5
91
perror ("open()");
exit (1);
}
I
I
Pentru a testa programul, vom crea cinci fiiere de tip fifo cu ajutorul
comenzii mkfifo, apoi vom lansa n fundal cinci instane ale programului (presupunem c n urma compilrii a fost generat executabilul cu numele ring).
Ieirea va fi redirectat n cinci fiiere corespunztoare celor cinci staii al cror
coninut va fi listat la finalul execuiei.
Un posil;>il rezultat este cel de mai jos:
(infoiasi):-$
(infoiasi):-$
(infoiasi):-$
(infoiasi):-$
(infoiasi):-$
(infoiasi):-$
. [1] 2380
(infoiasi):-$
[2] 2381
(infoiasi):-$
[3] 2382
mkfifo
mkfifo
mkfifo
mkfifo
mkfifo
ring 1
1
2
3
4
5
2 >A &
92
Atelier de programare n
reele
de calculatoare
Capitolul 6
6.1
Am
fiier
Duplicarea descriptorilor
vzut
returneaz
efectum
un descriptor de
diverse operaii de
intrare/ieire.
94
reele
de calculat oare
De reinut faptul c descriptorul nou alocat de dup () este cel mai mic
descrip tor liber (nchis) disponibil.
Primiti va dup2 () se comport similar cu dup () , _cu deosebirea c poate
(),
fi specificat explicit care va fi noul descriptor duplica t. Dup apelul dup2
,
operaie
de
descrip torul newfd va indica acelai fiier ca i oldfd. Dac, nainte
care
descrip torul newfd era deschis, atunci acesta este mai nti nchis, dup
se realizeaz duplicarea.
Ambele primitiv e returneaz descriptorul nou creat (n cazul lui dup2 O
egal cu newfd) sau valoarea -1 n caz de eroare.
6.1.1
Exem ple
de cod realizeaz redirec tarea
deschis avnd descrip torul fd:
Urmtoarea secven
fiier
ieirii
standar d spre un
<stdio. h>
<stdlib .h>
<unistd .h>
<sys/w ait.h>
r
I
Duplicarea descriptorilor.
Redirectri
void
who_wc () /* who I wc -1 */
{
int pfd(2];
I* un pipe */
/* cream pipe-ul */
if (pipe (pfd) == -1)
{
case -1:
fprintf (stderr, "fork - 1\n");
exit (1);
/* copilul */
case O:
close (1);
/* duplicam descriptorul de scriere al pipe-ului
la iesirea standard (1) */
if (dup (pfd[1]) != 1)
{
case -1:
fprintf (stderr, "fork - 2\n");
exit (1);
case O:
/* copilul */
close (O);
95
Atelier de programar e n
96
reele
de calculatoa re
/* parintele */
I* inchidem pipe-ul, nu-l folosim deloc */
close (pfd [O]) ;
close (pfd[l]);
I* asteptam terminare a copiilor */
while (wait (NULL) != -1)
}
int
main () /* programu l principa l */
{
who_wc ();
return O;
6.2
i
la acest
1.
Exerciii
sfrit
creeaz
exerciii
spre rezolvare:
(printe) citete
pn la sfritul
copil;
primului
pipe
primul copil primete caracterel e de la printe i selecteaz doar
literele mici pe care le trimite printr-un alt pipe ctre cel de-al doilea
copil;
date. txt
Duplicarea descriptorilor.
Redirectri
97
2.
va
afia
productor-consumator
astfel:
comun
printe;
printele
productor;
n general, productorii scriu n pipe un numr oareca re de caractere, iar consum atorii citesc din pipe, caract er cu caracte r, ct timp
acest lucru este posibil.
Productorii
vor avea
printele
urmtorul
compo rtamen t:
produc e un
numr
unul dintre
productori
cel
puin
le
n
98
3.
reele
de calculatoare
k
~~
Rezolvri
6.3
Exerciiul
3. Shell
complet
a problemei
<unist d.h>
<stdio .h>
<strin g.h>
<stdli b.h>
<sys/t ypes.h >
<sys/s tat.h>
<fcntl .h>
<signa l.h>
<termi os.h>
<diren t.h>
"keys. h"
*I
#defin e TEMP_MASK
11
/tmp/shellXXXXXX"
implementrii
I
l
I
I
Duplicar ea descriptorilor.
char *HISTORY;
wint ifd = -1, ofd = -1, hfd
int lines in hist = O;
-..,. . int curent_ line = -1;
int prompt_ length = O;
.nt SaveOut put;
. _ i~t Saveinp ut;
~.-:(i.'1I1t LastErr or = O;
r
-u
Redirectri
99
-1;
. UJ
afisare prompt */
-zy id Wri tePromp t () ;
~. "'"'/ functia de termina re */
Ll
char *p;
struct dirent **fisie re;
int nr = 1, n, i, index;
int files[10 00], cf =O;
char File [50] ;
char com[50] ;
char wrong = O;
-1)
== O))
nr++;
files [cf++]
}
i;
O)
Atelier de programare n
100
cf--;
if (cf < O)
reele
de calculatoare
retur n -1;
}
etrul */
/* daca avem unul singu r si este egal cu param
&&
O)
==
cf
(
(
f
i
n (com )))
(strl en (fisie re[fi les[O ]]->d _nam e) == strle
{
if (cf > O)
{
prin tf ("\n" );
for (i = O; i <= cf; i++)
prin tf ("%s \n", fisie re [file s [i]]-> d_na me);
whil e (1)
{
len)
wrong = 1;
break ;
}
if (wrong == 1)
{
-- O)
if (strc mp (fisie re[fi les[O ]]->d _nam e, com)
{
}
I
j
Duplicarea descriptorilor.
Redirectri
101
void
o_to_ line (int lineno )
int c = 1; /* liniil e se consid era incepa nd de la 1 */
char buffer ;
lseek (hfd, O, SEEK_SET);
while ((c < lineno ) && (read (hfd, &buffe r, 1)
if (buffe r == '\n')
c++;
}
void
et_li ne (int lineno , char *buffe r)
char *P
= buffer ;
if (linen o < 1)
{
}
buffer = NULL;
return ;
i f ( *P
{
1)
== ' \n' )
*P = '\0';
break;
}
p++;
}
}
if (*buff er
return ;
'\n')
int
GetKey ()
{
1))
102
reele
if (bu ffer == O)
read (O, &bu ffer , 1);
tcse tatt r (O, TCSANOW, &sa ve_t erm );
retu rn buf fer;
}
void
_LINE)
read_command (cha r *cm dlin e, int MAX
{
int buf;
int c = -1;
swit ch (buf )
{
case BACKSPACE:
if (c >= O)
{
c--;
brea k;
case BREAK:
Iesi re (O);
case KEY_DOWN:
if (lin es_ in_h ist == O)
brea k;
-1)
if (cur ent_ line
k;
brea
O)
if (cur ent_ line
cure nt_l ine = 1;
if (cur ent_ line < line s_in _his t)
{
int i;
cure nt_l ine+ +;
for (i = O; i < c; i++)
prin tf ("\b \b") ;
get_ line (cur ent_ line , cmd line );
c = strl en (cm dlin e);
Duplicarea descriptorilor.
Redirectri
el se
{
int i
for
= O; i < c; i++)
printf ("\b \b");
curent _line = -1;
bzero (cmdli ne, MAX_LINE);
(i
= O;
case KEY_UP:
if (lines _in_h ist == O)
break;
if (curen t_line == O)
break;
if (curen t_line
-1)
{
int i;
curent _line = lines_ in_his t;
for (i = O; i < c; i++)
printf ("\b \b");
get_li ne (curen t_line , cmdlin e);
c = strlen (cmdli ne);
printf ("%s", cmdlin e);
fflush (stdou t);
break;
}
int i;
curen t_line --;
for (i = O; i < c; i++)
printf ("\b \b");
get_li ne (curen t_line , cmdlin e);
c = strlen (cmdli ne);
printf ("%s", cmdlin e);
fflush (stdou t);
break;
}
break;
case KEY_LEFT:
case KEY_RIGHT:
break;
case TAB:
{
int i, rez;
rez = tab_co mpleti on ();
i f (rez == 1)
{
int 1 = strlen (cmdli ne);
for (i =O; i < (c + promp t_leng th); i++)
103
104
reele
de calculatoare
if (rez >= 1)
{
brea k;
defa ult:
if (c == -1)
{
cmdl ine[O ]
cmdl ine[1 ]
c = 1;
(cha r) buf;
O;
el se
{
c++;
cmd line[ c - 1] = (cha r) buf;
cmd line[ c] = '\0';
}
Redirectri
Iesire (2);
lines_in_ hist = O;
while (read (hfd, &buf, 1)
if (buf == '\n')
lines_in_ hist++;
lseek (hfd, O, SEEK_SET);
return;
1)
close (hfd);
if ((hfd =open (HISTORY, O_RDWR)) == -1)
{
/* afiseaza prompt-u l */
void
WriteProm pt ()
{
char i;
char buf[400] ;
prompt_l ength = O;
for (i =O; i < strlen (Prompt); i++)
switch (Prompt[ i])
{
I
I
case '$':
i++;
switch (Prompt[ i])
{
case 'u':
printf ("%s", USERNAME);
prompt_l ength += strlen (USERNAME);
break;
case '$':
printf ("$");
prompt_le ngth++;
break;
case 'd':
getcwd (buf, 400);
i f (strcmp (buf, "/") != O)
{
el se
{
105
Atelier de programa re n
106
reele
de calculato_a_r_e____ _____
break;
}
b;reak;
default :
{
}
}
char *
itoa (int nr, char *buffer )
{
char aux[10] ;
char c = O, i;
char *P = buffer;
if (nr
== O)
*P = 'O';
*(p + 1) = '\0';
return buffer;
}
for (i
1; i >= O; i--)
aux[i];
*P
p++;
}
*P = '\O';
return buffer;
}
f * functie de alocare */
char *
alocare (int marime)
{
char *p;
if ((p = (char *) malloc (marime )) ==NULL)
{
return p;
}
Duplicarea descriptorilor.
Redirectri
107
11
11 ) )
NULL)
do
{
strcat (Return , 11 11 ) ;
if (expand are (p, Return)
return 1;
1)
el se
{
p
}
11
11 ) ;
while (p !=NULL );
strcpy (cmdlin e, Return) ;
return O;
int
expanda re (char *exp, char *list)
\ {
struct dirent **fisie re;
int n, c = O, i, j, k;
char has_las t = O;
char *param[ 10], *p;
char *index[ 10];
char EXPAND[100];
char *DIRECTORY;
char lista[10 00];
I
I
-1)
Atelier de programare n
108
reele
de calculatoare
1;
if (EXPAND[O] == '*')
{
if
{
el se
param[c++] = p;
while ( (p = strtok (NULL,
11
*")) ! = NULL)
if (has_last == 1)
{
param[c]
~~~
~~~--~~~~~~
= NULL;
char wrong = O;
/* verifica daca toti sunt '*' *I
for (j = O; j < c; j++)
i f (strcmp (param[j], "*") != O)
wrong = 1;
i f (wrong == O)
{
Redirectri
f~
~~!~re
I{
I
= O;
for (j = O; j < c; i++)
if (strcmp (param [j], "*") != O)
if (index [j] == NULL)
wrong = 1;
if (wrong == 1)
continu e;
wrong = O;
for (j =O; ((j < (c - 1)) && (wrong ==O)); j++)
for (k = (j + 1); ((k < c) && (wrong ==O)); k++)
if ((strcm p (param [j], "*") != O)
&& (strcmp (param [k], "*") !=O))
if (index [j] >= index[k ])
wrong = 1;
if (wrong == 1)
continu e;
strcat (lista, fisiere [i]->d_ name);
strcat (lista, " ") ;
(int cod)
*I
109
110
reele
de calculato are
free (USERNAME);
free (HISTORY);
exit (cod);
}
int i;
char *p;
for (i = O; i < 255; i++)
if (argv[i] == NULL)
break;
el se
{
p =alocar e (8);
argv[i] = itoa (LastEr ror, p);
continu e;
}
if (strcmp (argv[i ], "$$")
{
== O)
p =aloca re (8);
argv[i] = itoa (getpid (), p);
continu e;
}
if (strcmp (argv[i ], "$!") ==O)
{
p =aloca re (8);
argv[i] = itoa (getppid (), p);
continu e;
}
i f (strcmp (argv[i ], "$0") == O)
{
argv[i] = BASH_NAME;
}
}
}
Redirectri
if ( *P ! = '" ')
{
argv[c+ +]
continu e;
p;
I
l
argv[c] = NULL;
SearchF orVars (argv);
if ((c >= 2) && (strcmp (argv[c - 1), "&")
{
O))
wait_f or_chi ld = O;
argv[c - 1] = NULL;
case -1:
printf ("Fork error\n ");
return 2;
case O:
111
112
reele
de calculat oare
==
if ((fdl
{
NULL)
= open
(OUTPUT, O_RDWR))
==
-1)
==
-1)
case -1:
printf
return
case O:
execvp
printf
return
Duplicar ea descriptorilor.
Redirectri
113
case -1:
printf
return
case O:
execvp
printf
return
}
if (wait_fo r_child == 1)
wait (&LastE rror);
close (fd1);
dup2 (b_in, O);
return O;
if ((fd2
{
-1)
case -1:
printf
return
case O:
execvp
printf
return
}
if (wait_fo r_child == 1)
wait (&LastE rror);
close (fd1);
close (fd2);
dup2 (b_out, 1);
dup2 (b_in, O);
return O;
-1))
114
reele
de calcula toare
void
MoveO utputT olnput ()
{
if ((fd2
{
lI
1)
/* creeaz a un fisier */
void
Create File (char *filena me)
{
int fd;
char *P
= filenam e;
while (*p
== ' ')
p++;
filenam e = p;
if ((fd = creat (filena me, S_IRUSR I S_IWUSR))
{
close (fd);
}
void
Transf erTo (char *dest, char *Sourc e)
{
if ((dfd
{
== -1)
-1)
Redirectri
char *p;
char SaveLin e[1000];
char Buffer;
if ( (p = str str ( cmdline ,
{
11
I 11 ) ) == NULL)
'
11
>"))
!=NULL)
int i = O
strcpy (S~veLine, p);
*P = '\O';
SaveLin e[O] =' ';
while (SaveLin e[i++] == ' ');
i--;
int i = O
strcpy (S~veLine, p);
*P = '\O' ;
SaveLin e[O] =' ';
while (SaveLin e[i++] == ' ');
l
r
i--;
I
I
return O;
115
116
reele
de calculat oare
close (ifd);
if ((ifd = open (TEMP, O_RDWR)) == -1)
{
close (ofd);
if ((ofd = open (TEMP2, O_RDWR)) == -1)
{
i
II
retur n;
if
if
{
}
}
if
{
if
{
}
O)
O)
== ,-,)
4)
O)
7)
O)
( }return O;
void
print _info s O
char *p;
SIG_ERR)
Redirectri
117
118
reele
de calcula toare
O))
I* af iseaza prompt */
Wri teProm pt () ;
/* citest e comanda */
read_command (cmdli ne, 1000);
printf ("\n") ;
if (cmdli ne[O] == '\n')
contin ue;
I* verifi ca daca e comanda specia la */
if (SpecialCommand () == 1)
contin ue;
/* verifi ca redire ctari */
if (Check ForPip es () == O)
MyExec (NULL, NULL, cmdlin e);
return O;
}
if (signum == SIGTERM)
Iesire (SIGTERM);
coninnd
#ifnde f __ MYKEYS __
#defin e __ MYKEYS __ 1
#defin e KEY_UP
#defin e KEY_DOWN
16"131
16987
I* sageat a in sus *I
I* sageat a in jos *I
#defin e
#defin e
#defin e
#defin e
#defin e
#defin e
#defin e
KEY_LEFT 17499
KEY_RIGHT 17243
BACKSPACE 127
TAB 9
SPACE 32
ENTER 13
BREAK 3
Redirectri
/* sagea ta sting a */
/* sagea ta dreap ta */
#endi f
posibil
urmtoarea:
Shell [lrc shell _fina l]$ rm *Shell [lrc shell _fina l]$ ls
Make file keys. h shell shell .c
1(~ Shell
[lrc shell _fina l]$ ls -l *.c
-rwxr -xr-x
1 lrc
lrc
21459 Jun 9 22: 35 shell . c
Shell [lrc shell _fina l]$ promp t Salut $u:>
Salut lrc:> exit
Jr
119
Capit olul 7
Interfaa
soc ket
7 .1
Exist
comunicaii
comunicaii fr
Comunicaiile
se
realizeaz
dup
modul n care
singur direcie;
Interfaa
socket
121
Comunicaiile
t
e
e
1:
le
11
)-
TCP (Transm ission Control Protocol} este un protocol orientat- conexiu ne care ofer posibilit atea de a realiza comunicaii full duplex sigure. Se
bazeaz pe protocol ul IP. TCP este de departe cel mai folosit
protocol n
comunic area n reele conectat e la Internet . Protocol ul TCP a fost definit
n mod oficial n docume ntul RFC 1 793.
UDP (User Datagra m Protocol} reprezint protocolul utilizat pentru comunicaii nesigure n mod neconec tat (prin intermed iul datagram
elor).
Detalii despre specificaiile protocul ui UDP pot fi gsite n RFC 768.
ICMP (Interne t Control Message Protocol} este folosit pentru tratarea
erorilor i controlul informaiilor vehiculate n Internet . Folosete protocolul IP pentru realizarea schimbului de date. n mod normal, procesele
utilizato r nu au nevoie s acceseze ICMP, deoarece mesajele acestuia sunt
procesat e de ctre software-ul TCP /IP.
IP (Interne t Protocol} reprezint protocolul de baz pentru UDP, TCP i
ICMP. Procesele utilizato r folosesc doar TCP sau UDP, folosirea direct
a protocol ului IP fiind rar ntlnit.
re
ARP ( Address Resoluti on Protocol) este un protocol utilizat la translatarea adreselor IP n adrese hardware (Etherne t).
RARP (Reverse Address Resoluti on Protocol}
ware n adrese Internet .
translateaz
adresele hard-
ar
~le
1 Documen tele
RFC (Request For Comment s) sunt documentele care descriu, reglemecanismele intime ale Internetului, n special ale protocoalelor.
menteaz i actualizeaz
Atelier de programar e n
122
reele
de calculatoa re
TELNET
SMPT
FTP
7~ I
!
RTP
//
fr,ans.m is.s ion
RTCP
Control Protocol
SNMP
DNS
RlP
DHCP
OSPF
r1eM~
IGMP
Internet ProtC>CQI
ARP
Ethernet
7.2
Interfaa
Token
Token
Bus
Ring
FGOi
socket
socket
reprezint
>
(,'
Interfaa
/7''
Primitiv
socket( )
bind()
listen( )
accept( )
connect O
send()
receive ()
close ()
shutdow n()
~a
)-
X
)l
i1l
tU
123
'( Tabela
socket
,,
7.~;/Primitivele
care
acioneaz
asupra socket-urilor
Descriere
Creeaz un nou punct de capt al comunicaiei (socket)
Ataeaz o adres local la un socket
Permite unui socket s accepte conexiuni
Blocheaz. apelantu l pn la sosirea unei cereri de conexiune
(utilizat de serverul TCP)
Tentativ (activ) de a stabili o conexiune
(utilizat de clientul TCP)
Trimite date prin intermed iul unui socket
Recepioneaz date prin intermed iul unui socket
Inchide descriptorul de socket; se elibereaz conexiunea
Inchide direciona:! descriptorul de socket;
se elibereaz conexiunea
7.2.1
le
ll-
124
reele
de calcula toare
UNIX);
AF_UNIX stabilete domeniul de comunicare local (domeniul
ntre procese aflate pe aceeai
diferite, folosind stiva de 'protocoale TCP /IP (do-
sau pe maini
meniul Intern et).
main
comunicaii
or
Argum entul domain permit e deci stabili rea format ului adreselor mainil
va
socket
implicate n transfe rul de date. Pentru domeniul Interne t, fiecare
numr de
avea asociat o adres) format din adresa IP a mainii gazd i un
8).
ul
16 bii, local gazdei respective, denum it port (vezi capitol
a putea folosi i alte
Interfaa socket este suficient de general pentn,i
e precum
domenii de transmisie, recurg nd la protocoale prezente pe sistem
AF se poate
Novell (AF _IPX) sau Apple (AF _APPLETALK). n locul prefixului
, consta nta
(aadar
Family
ol
utiliza i PF, PF fiind prescu rtarea de la Protoc
AF _UNIX este echivalent cu PF _UNIX).
modal itatea de realizare a comunicrii. Cele
,/Tipu l socket-ului se refer la
mai utiliza te dou valori sunt:
trrilor.
fr
conexiune,
nesigur,
folosind
S.atagrame.
ofer
un acces la protocolul ;l
Se mai poate folosi consta nta SOCK_f\AW care
( e.g. protocolul IP), de nivel inferio ;/Pent ru mai multe detalii,
1
manualul.
t penArgum entul protoc ol specific protocolul particu lar care va fi utiliza
ntldes
tru transm isia datelo r. Valoarea O pentru acest argum ent este foarte
protocol permis cu perechea
nit. Aceast a permit e sistem ului s aleag primul
egal cu
de valori specificate pentru familie i tip. De exemplu, pentru domain
de transp ort
AF _!NET i type egal cu SOCK_STREAM se va considera protocolul
egal cu
TCP, iar pentru cazul n care domain este egal cu AF _!NET i type
UDP.
SOCK_DGRAM se va consid era implicit protocolul de transp ort
de fiier
n caz de succes, primit iva socke t() returneaz un descriptor
errno
ila
eaz -1 i variab
ataat socket-ului, iar n caz de eroare, se return
,
descrie proble ma survenit.
reea
consultai
,,1.
Interfaa
7.2.2
socket
125
Exem plu
Ne propun em n continu are s crem mai multe socket-u ri, fixnd diferite
valori
pentru cele trei argume nte ale primitivei socket O. Vom observa c anumit
e
combinaii sunt invalide, return ndu-se eroare.
#includ e
#includ e
#includ e
#includ e
#includ e
<sys/ty pes.h>
<sys/so cket.h>
<netin et/in.h >
<stdio. h>
<errno. h>
l
l
ll
ii
l-
l:a
u
rt
:u
;)[
lO
~f
126
IPPROTO_ESP,
IPPROTO_AH,
IPPROTO_ICMPV6,
IPPROTO_NONE,
IPPROTO_DSTOPTS,
IPPROTO_MTP,
IPPROTO_ENCAP,
IPPROTO_PIM,
IPPROTO_RAW,
I*
/*
/*
/*
/*
/*
I*
I*
I*
reele
de calculatoare
};
char *PROTOCOL_names[25] = {
"Dummy proto col for TCP.",
"IPv6 Hop-by-Hop optio ns. ",
"Inte rnet Cont rol Message Proto col." ,
"Inte rnet Group Management Proto col." ,
"IPIP tunne ls (olde r KA9Q tunne ls use 94)." ,
"Tran smiss ion Cont rol Proto col." ,
"Exte rior Gateway Proto col." ,
"PUP proto col." ,
"User Datagram Proto col." ,
"XNS IDP proto col." ,
11
"SO Trans port Proto col Class 4 . '
"IPv6 head er.",
"IPv6 routi ng head er.",
"IPv6 fragm entat ion head er.",
"Rese rvatio n Proto col." ,
"Gen eral Routi ng Enca psula tion." ,
"enca psula ting secu rity paylo ad.",
"auth entic ation head er.",
"ICMPv6",
"IPv6 no next head er.",
"IPv6 desti natio n optio ns.",
"Mul ticas t Trans port Proto col." ,
"Enc apsul ation Head er.",
"Prot ocol Indep enden t Mult icast .",
"Raw IP pack ets."
};
int
main O
{
i de tablo u */
int ii = 10, ij = 6, ik = 26; /* valor i maxime indic
*/
I* itera tori
int i, j, k;
sd;
int
Interfaa
socket
127
-1)
case EPRDTDNDSUPPORT:
printf ("Nu este suporta t protoco lul\n");
break;
case ENFILE:
printf
("Nu este suficien ta memorie "
"pentru alocare a unui nou socket\ n");
break;
case EMFILE:
printf ("Depas ire in tabela de alocare a fisierel or\n");
break;
case EACCES:
printf
("Nu avem permisiu nea de a crea un socket "
"de tipul sau protoco lul specifi cat\n") ;
break;
case ENOBUFS:
case ENOMEM:
printf ("Nu este suficien ta memorie \n");
break;
case EINVAL:
Atelier de programare n
128
reele
de calculatoare
prin tf
("Pr otoc ol necu nosc ut sau fami lie de "
"pro toco ale inex isten ta\n ")i
brea k;
}
cont inue ;
}
clos e (sd) ;
}
retu rn O;
}
7.2. 3
Aceast primitiv
utilizat
pent ru
7 .2.4
Exe mpl u
ntre
Un exemplu simplu de trans mite re de mesaje
este cel de mai jos:
dou
procese
etpa ir() */
/* Com unic atie intr e proc ese folo sind sock
#inc lude <sys /type s.h>
#inc lude <sys /soc ket.h >
#inc lude <net inet/ in.h >
#inc lude <std io.h>
#inc lude <err no.h >
#inc lude <uni std.h >
#inc lude <str ing.h >
#inc lude <sys /wai t.h>
printe-copil
Interfaa
socket
int
main ()
{
int sd[2];
/* mesajele vehiculate */
char *P = "Eu sunt parintele";
char *c = "Eu sunt copilul";
char buf[100];
/* se creaza perechea de socket-uri, folosindu-se
domeniul de adrese AF_UNIX */
if (socketpair (AF_UNIX, SOCK_STREAM, O, sd) == -1)
{
l
n
~i
case -1:
/* eroare*/
perror ("Eroare la fork() ");
exit (1);
break;
case O: /* fiul */
I* citim din socket mesajul *I
if (read (sd[1], buf, 100) <O)
{
1il
\!
/* trimitem EOF */
clase (sd[1]);
/* am terminat */
exit (O);
default:
/* parintele */
I* trimitem mesajul parintelui */
if (write (sd[O], p, 100) < O)
{
129
Atelier de programare n
130
reele
de calculatoare
exit (3);
}
t: '%s'\n ",
print f ("Pro cesul cu PID-u l %d (parin tele) a primi
getpi d O , buf) ;
/* astept am termi narea copil ului */
if (wait (NULL) < O)
{
/* gata! */
close (sd[O ]);
return (O);
}
}
7.3
Exerciii
) s se conceap
1. Folosi nd perech i de socket -uri gener ate de socke t pair(
ie matem atun progr am care citete de la intrar ea stand ard o expres
proces e copil. Fiecar e proces
ic care va fi transmis spre evalua re unor
-et-impera,
copil va evalua o sub-ex presie matematic, n manier divide
rezult atul
return nd prin socket valoar ea ei. Proce sul printe va primi
vor putea {
final i-l va afia la ieirea standa rd. Expresiile matem atice
I
teze.
paran
i
uzuali
conine opera nzi ntreg i, opera tori aritme tici
2.
reea de tip
se rescrie exerciiul referit or la detect area staiilor dintr- o
-uri.
socket
ns
magistral (propu s n capito lul 5), utiliz ndu-se
<
<
! ,,y.
Capitolul 8
1
)[.'
8.1
p
~t
~es
ra,
tul
;ea
tip
n cadrul aplicaiilor n reea paradigma cel mai frecvent folosit este modelul
client/serv er, n care un server ofer anumite servicii anumitor clieni rulnd
pe aceeai main sau la distan (pe alte calculatoare conectate la reea).
Serverul poate satisface cererile provenite de la clieni n mod iterativ (la
un moment dat serverul va deservi cereri provenite de la un singur client,
secvenial pentru toi clienii lui) sau concurent (mai multe cereri, provenite de
la clieni multipli, vor fi procesate simultan). Serverele concurente sunt folosite
mai ales atunci cnd rspunsul nu poate fi transmis napoi imediat sau n
cazul n care trebuie realizate comunicaii suplimenta re cu clientul. De obicei,
serverele concurente folosesc protocoale de comunicaie orientate conexiune.
Astfel, serverul concurent rspunde oricror cereri client independen,t de toi
.
.
.
,J
!
,
I
>"'1
,
, , ,,
ce1lal1 clieni.
t'
, \, p
, "Y'JJ.<l/JJ1!J ,, ' 1 ,_1
1-s._ .
Comunicar ea dintre server i clienii si se va realiza prin intermediul suitei
de protocoale TCP /IP, prin intermediul socket-urilor, utilizndu-se stream-uri
de octei (protocolul TCP) sau datagrame (protocolul UDP). Despre UDP vom
discuta detaliat n capitolul 9.
t
8.2
creeaz
respect
ordinea
pregtirea
urmtoarelor
clienii;
bind()
ataeaz
socket-ul la port;
ataa
Atelier de programare n
132
reele
de calculatoare
listen() pregtete socket-ul pentru ascultarea portului n vederea stabilirii conexiunii cu clienii;
accept() ateapt realizarea unei conexiuni c:u un anumit client (acest
apel blocheaz programul pn la apariia unei cereri de conectare din
partea unui client);
procesarea cererilor clientului - schimb de mesaje ntre server i client
folosindu-se descriptorul de socket returnat de accept (), prin apelul
primitivelor read() i writeO;
general
direcional
a conexiunii cu clientul.
a programelor server
urmrit
clientului TCP
c
s
cerere
}
rspuns
es
server TCP
client TCP
st
133
aceast
8.2.1
11
strncbff partlculnr
ie
u
sin_f amil y;
sin_ port;
struc t in_ad dr
unsig ned char
sin_a ddr;
sin_z ero[S ];
Atelier de programare n
134
reele
de calculatoare
8.2. 2
conexiuni de
portului, serverul va trebui s atepte viitoare
a apelul
utiliz
ru aceasta vom
la diveri clieni i s le rezolve cererile. Pent
liste n O urm at apoi de acce pt O.
Prot otipu l primitivei liste n() este:
Dup ataarea
8.2. 3
Acceptarea
propriu-zis
'.
'
135
duplex ntre server i client. Noul descriptor va putea fi folosit pentru a trimite
i a recepiona date via reea prin mijlocitori precum send O sau wri te() i
recv() sau read(), respectiv.
Argumentul addr va conine informaii despre adresa IP i portul folosite
de clientul conectat la server, iar lungimea acestei structuri va fi stocat de
ultimul argument addrlen.
a
Li
.e
t
u
r-
8.2.4
ul
te
er
ie
Primitivele send()
Primitivele send()
recv()
#include <sys/types.h>
#include <sys/socket.h>
o
,te
~e-
de
lul
de
8.2.5
Primitivele el o se()
Dup
shutdown()
ui a
:aie
'.
'
Atelier de programare n
136
reele
de calculatoare
8.3
Clien t TCP
n cazul unui client TCP, vom folosi n locul apelului accept () primiti va dual
connec t O care are forma urmtoare:
#includ e <sys/ty pes.h>
#includ e <sys/so cket.h>
);
int connec t(int sockd, struct sockadd r *addr, socklen _t addrlen
137
write(), read()
shutdown()
close()
8 .4
Conversia datelor
folosit
,al
,:_+
'f'1... ,'"
.
.,
j'';
'\"'
"' ..J
-~ ,
:..-'.
'
''
.:'<fi
" t ~ .. ~
i va
er i
'
'I l;
utilizat
.i'
,1
')
_.,,}::r
de
octei)
de la
gazd
la
reea
octei)
octei)
de la
de la
reea
reea
la
la
gazd
gazd
l:
~are
'
'~.~ r'Jt}~/
de pro-
""
"t
Atelier de programare n
138
reele
de calculatoare
8.5
dat
are
urmtoarea form:
capt
al conexiunii rea-
.n
139
Exemplu
8.6
I
s)
o
t
ru
server-tcp.c
id
ria
.t
~re
/
#include
#include
#include
#include
#include
#include
#include
#include
<sys/types.h>
<sys/socket.h>
<netinet/in.h>
<errno.h>
<unistd.h>
<stdio.h>
<string.h>
<stdlib.h>
/* portul folosit /
#define PORT 8081
/ codul de eroare returnat de anumite apeluri /
extern int errno;
/* programul /
ea-
int
main O
{
I* cream un socket /
if ((sd = socket (AF_INET, SOCK_STREAM, O))
{
-1)
Atelier de programare n
140
reele
de calculatoare
return errno;
}
int client;
int length = sizeof (from);
printf ("Asteptam la portul %d ... \n", PORT);
fflush (stdout);
I* acceptam un client
(ne vom bloca pina la realizarea conexiunii) */
client= accept (sd, &from, &length);
*
#
#
141
el se
printf (" trasmiter e cu succes.\n ");
I* am terminat cu acest client, inchidem conexiun ea*/
close (client);
}
I* while */
/* main */
Codul
surs
client-tc p.c
I*
142
#inclu de
#inclu de
#inclu de
#inclu de
#inclu de
#inclu de
#inclu de
reele
de calculatoare
printf ("Sint axa: %s <adres a_serv er> <port> \n", argv[O ]);
return -1;
/* stabil im portul */
port= atei (argv[ 2]);
-1)
143
/* ne conectam la server */
if (connect (sd, (struct sockaddr *) &server,
sizeof (struct sockaddr)) == -1)
{
Atelier de programare n
144
reele
de calculatoare
all:
gcc server-tcp.c -o server-tcp
gcc client-tcp.c -o client-tcp
clean:
rm -f
*-
client-tcp server-tcp
145
Exerciii
8. 7
1.
2.
3.
se scrie un server TCP concurent care accept maxim i clieni simultan, ateapt un numr N i returneaz fiecrui client lista numerelor
prime de la 1 pn la numrul N.
4.
Scriei
Dup
;e
n
~i
>r
it
la
:e
1-
ei
aei
ta
B,
:a
i
t
te
i returneaz
8.8
Rezolvri
Exerciiul
3. Numere prime
Atelier de programare n
146
apariia
reele
de calculatoare
aceast situaie,
se va ignora
semnalul SIGPIPE.
#include
#include
#include
#include
#include
#include
#include
#include
<sys/types .h>
<sys/socke t.h>
<netinet/in .h>
<unistd.h>
<error.h>
<string.h>
<stdlib.h>
<signal.h>
I*
portul folosit */
const int PORT_SERVER = 9001;
/* numarul maxim de clienti acceptati */
const int CLIENTI_MAXIM = 10;
extern int errno;
int ds;
int de;
O;
int nr
I*
I*
eroarea returnata */
descriptor pentru server */
/* descriptor pentru client */
I* numarul de clienti *I
void
semnal (int nr_semnal) /* functia de tratare a semnalelor */
{
if (nr_semnal
==
SIGCHLD)
wait (NULL);
nr--; /* am pierdut un client */
return;
}
I*
int k;
for (k = 2; k * k <= i; k++)
if ((i %k) == O)
return O;
return 1;
}
void
client () I* functia de tratare a clientu lui */
147
148
reele
de calcula toare
int
main () /* progra mul princi pal */
{
SIG_ERR)
SIG_ERR)
-1)
if (liste n (ds, 5)
==
-1)
);
printf ("Aste ptam client i la portul %d ... \n", PORT_SERVER
while (1)
{
/* accept am un client */
de= accept (ds, NULL, NULL);
I* am ajuns la numarul maxim de client i? */
if (nr == CLIENTI_MAXIM)
case O:
client O;
case -~:
perror ("fork() ");
break;
default:
break;
}
149
Cap itolu l 9
Modelul client/server-_. UD P
n cadrul acestui capitol se prezint maniera de concepere
a programelor server iterative i a programelor client
utiliznd protocolul de transport UDP (User Datagram
Protocol).
9.1
clienii;
u a ataa
struc turilo r de date (coninute n sock addr _in) pentr
socket-ul la portu l folosit de aplicaie;
pregtirea
bind ()
ataeaz
socket-ul la port;
151
clientului UDP
cerere
rspuns
tl
p
li
si
t,
i
ea
server UDP
l
l
client UDP
general:
#include <sys/types.h>
#include <sys/socket.h>
int recvfrom(int sockd, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);
urmtoarea form:
#include <sys/types.h>
#include <sys/socket.h>
oa
int sendto(int sockd, const void *msg, size_t len, int flags,
const struct sockaddr *to, socklen_t tolen);
9.2
nt,
~ i
Exernplu
Atelier de programare n
152
Sursa serverului
(stocat
fiierul
reele
de calculatoare
server-udp .c
#include
#include
#include
#include
#include
#include
<sys/types .h>
<sys/socke t.h>
<stdio.h>
<netinet/in .h>
<errno.h>
<unistd.h>
/* portul folosit */
#define PORT 8081
codul de eroare returnat de anumite apeluri */
extern int errno;
I*
I*
programul */
int
main O
{
I*
*I
I* eroare la fork() */
case -1:
perror ("Fork error\n");
return errno;
/* copilul traieste ... *I
case O:
break;
/* parintele moare ... *I
default:
printf ("Serverul a fost lansat in fundal ... \n");
exit (O);
}
I* cream un socket */
if ((sd =socket (AF_INET, SOCK_DGRAM, O))
153
-1)
int bytes;
int length = sizeof (client);
/* while */
I* main */
Atelier de programare n
154
Urmeaz
reele
de calculatoare
client-udp.c
#include
#include
#include
#include
#include
#include
#include
<sys/types.h>
<sys/socket.h>
<stdio.h>
<netinet/in.h>
<errno.h>
<netdb.h>
<string.h>
I* programul */
int
main (int argc, char *argv[])
{
I* descriptorul de socket */
int sd;
/* structura folosita pentru conectare */
struct sockaddr_in server;
/* mesajul trimis */
char buffer[100];
int length;
/* exista toate argumentele in linia de comanda? */
i f (argc ! = 3)
{
/* stabilim portul */
port= atoi (argv[2]);
I
I
I
155
/* cream socketul *I
if ((sd = socket (AF_INET, SOCK_DGRAM, O))
-1)
Atelier de programare n
156
reele
de calculatoare
9.3
1.
Exerciii
Modificai
s
irul
primit de la client
2.
3.
9.4
maini
Rezolvri
Exerciiul
<stdio.h>
<string.h>
<sys/socket.h>
<sys/types.h>
<sys/time.h>
<unistd.h>
<netinet/in.h>
<netdb.h>
"erori.h"
157
int sd, i;
struct sockadd r_in adr_des t; /* adresa serveru lui 'daytine ' */
char s[70], *st;
struct tm timp;
/* va contine timpul & data */
/* creare socket */
if ((sd = socket (AF_INET, SOCK_DGRAM, O))
-1)
:i
eroare ();
exit (1);
}
eroare ();
exit (1);
}
Atelier de programare n
158
reele
de calculatoare
switch (errno)
{
case EPROTONOSUPPORT:
perror ("Tipul protocolul ui folosit nu este suportat." );
break;
case EMFILE:
perror ("Tabela de procese este plina.");
break;
case ENFILE:
perror ("Tabela de descriptor i este plina.");
break;
case EACCES:
perror ("Nu se poate crea un socket "
"cu tipul si/sau protocolul dat.");
break;
case ENOBUFS:
perror ("Nu este suficient spatiu liber in buffer.");
break;
case EBADF:
perror ("Descript orul folosit nu este corect.");
break;
case EINVAL:
perror ("Portul este deja legat la un socket.");
break;
case ENOTSOCK:
perror ("Argument ul dat este nu e un descriptor de socket.");
break;
case EFAULT:
perror ("Pointeru l de adresa specificat este invalid.") ;
break;
case EMSGSIZE:
perror ("Lungimea specificat a este mai mica decat "
"lungimea mesajului care trebuie trimis.");
break;
case EWOULDBLOCK:
perror ("Socketul este creat non-blocan t "
"dar cererea este blocanta." );
break;
case ETIMEDOUT:
perror ("Timpul acordat coneex.iuni i a expirat.") ;
break;
case ENETUNREACH:
perror ("Nu ne putem conecta la adresa specificat a.");
break;
case EADDRINUSE:
perror ("Adresa este folosita deja.");
break;
default:
perror ("A survenit o alta eroare");
}
}
159
Capit olul 10
intrrilor /ieirilor
10.l
recurge
Pentru multipl exarea n manier sincron a intrrilor i ieirilor vom
rea:
urmtoa
este
la folosirea primitiv ei select () a crei sintax general
#includ e <sys/ti me.h>
#includ e <sys/ty pes.h>
#includ e <unistd .h>
int
select(
) ;
Pentru manipu larea elemen telor mulimilor de descrip tori (tipul fd_set)
se pun la dispoziie urmtoarele macro-u ri:
/* face multim ea vida */
FD_ZERO (fd_set *set);
/* seteaza un bit ('fd') din multim ea 'set') */
FD_SET (int fd, fd_set *set);
/* sterge un bit ('fd') din multim ea 'set') */
FD_CLR (int fd, fd_set *set);
/* testeaz a aparten enta lui 'fd' la multim ea 'set' */
FD_ISSET (int fd, fd_set *Set);
descrip tor i va corespu nde un bit n repreze ntarea
descrip tori dat de tipul predefi nit fd_set .
Fiecrui
I
mulimii
de
Multiplexa rea
intrrilor /ieirilor
161
10.2
Exemp le
II
I
t)
#include
#include
#include
#include
<sys/type s.h>
<sys/time .h>
<unistd.h >
<stdio.h>
/* programu l */
int
main O
{
de
Atelier de programare n
162
reele
de calculatoare
el se
printf ("Inca nu suntem gata de citire ... \n");
}
/* programul */
main (int argc, char *argv[])
{
I
I
I
I
I
l
163
/* exista argumentele? */
if (argc != 3)
{
/* setam valorile */
timeout.tv_sec =atol (argv[1]);
timeout.tv_usec =atol (argv[2]);
/* apelam select() pentru temporizare */
if (select (O, NULL, NULL, NULL, &timeout) < O)
{
return O;
}
Observai
execuia
programului, intro-
3. Apelul select() este folosit preponderent la realizarea de servere concurente, dup cum vom vedea din exemplul de mai jos.
I
:le.
surs
urmtorul:
server-tcp.c
lui
#include
#include
#include
#include
#include
#include
#include
#include
<sys/types.h>
<sys/socket.h>
<sys/time.h>
<netinet/in.h>
<unistd.h>
<error.h>
<stdio.h>
<arpa/inet.h>
Atelier de programare n
164
reele
de calculatoare
/* portul folosit */
#define PORT 8081
/* eroarea returnata de unele apeluri */
extern int errno;
/* functie de convertire a adresei IP
a clientului in .sir de caractere */
char *
conv_addr (struct sockaddr_in address)
{
/* adresa IP a clientului */
strcpy (str, inet_ntoa (address.sin_add r));
I* portul utilizat de client */
bzero (port, 7);
sprintf (port, ":%d", ntohs (address.sin_por t));
strcat (str, port);
return (str);
}
I* programul */
int
main O
{
Multip lexare a
intrrilor/ ieirilor
/* crear e socke t */
if ((sd = socke t (AF_INET, SOCK_STREAM, O))
{
165
-1)
I
I
l
l
166
reele
de calculatoare
/* apelul select() */
if (select (nfds+1, &readfd s, NULL, NULL, &tv) < O)
{
I*
I*
Multiple xarea
intrrilor /ieirilor
167
fd);
fflush (stdout) ;
/* inchidem conexiun ea cu clientu l */
close (fd);
/* scoatem si din multime */
FD_CLR (fd, &actfds );
}
}
}
/* for */
I* while */
/* main */
}
}
I* mesajul */
char buffer[1 00];
I* numarul de octeti cititi/s crisi */
int bytes;
bytes = read (fd, buffer, sizeof (buffer ));
if (bytes < O)
{
return bytes;
}
similar
cu cea de la capitolul 8
afia informaii
nu o voru mai
168
10.3
reele
de calculato are
Asinc ronism
II
I
j
J
'
'..J1.
<sys/typ es.h>
<sys/so cket.h>
<sys/tim e.h>
<netine t/in.h>
<unistd .h>
<error.h >
<string. h>
<stdlib. h>
<arpa/in et.h>
<signal. h>
MAX_CLIENTS 10 I* numar maxim de clienti *I
FULL "Nu mai pot fi accepta ti alti clienti ... \n"
MESSAGE "Mesaju l:"
MES_LEN strlen(MESSAGE)
;e,
ca
;le
char *
ConvAddr O
{
char *p;
char nr[10];
if ((p = (char *) malloc (25)) == NULL)
return inet_ntoa (address.sin_addr);
p = inet_ntoa (address.sin_addr);
bzero (nr, 7);
sprintf (nr, 11 :%d 11 , ntohs (address.sin_port));
strcat (p, nr);
return p;
JU,
ite
va
ere
void
tratare client ()
~lu
i a
char s = 1;
printf ( 11 [PID %d] A sosit un nou client de la %s ... \n 11 ,
getpid(), ConvAddr());
while (1)
{
FD_ZERD (&scriere);
FD_SET (cd, &scriere);
tv.tv_sec = O;
tv.tv_usec = O;
/* select cu multimea descriptorilor de scriere */
if (!select (cd+ 1, NULL, &scriere, NULL, &tv))
break;
/* se poate scrie, scriem efectiv */
i f (s == 1)
== O)
169
170
Atelier de programare n
reele
de calculatoare
= O;
continue;
s
}
1;
int
main (int argc, char *argv[])
{
SIG_ERR)
perror ("signal()");
return errno;
}
/* creare socket */
if ((sd = socket (AF_INET, SOCK_STREAM, O))
{
perror ("socket()");
return errno;
-1)
Multiplexarea
intrrilor /ieirilor
171
I* completare structura */
server.sin_family = AF_INET;
server.sin_port = htons (port);
server.sin_addr.s_addr = htonl (INADDR_ANY);
I* atasare la port */
if (bind (sd, &server, sizeof (server)) == -1)
{
perror ("bind()");
return errno;
}
FD_ZERO (&citire);
FD_SET (sd, &citire);
tv.tv_sec = 5;
tv.tv_usec = O;
if (select (sd + 1, &citire, NULL, NULL, &tv)
continue;
1 = sizeof (address);
bzero (&address, sizeof (address));
/* acceptarea unui nou client */
cd= accept (sd, &address, &l);
/* lansarea unui alt proces care sa trateze
cererile clientilor */
switch (fork ())
{
case -1:
shutdown (cd, 2);
close (cd);
perror ("fork() - 2");
continue;
case O:
tratare_client ();
default:
break;
}
}
}
O)
Atelier de programare n
172
Codul
surs
al clientului este
reele
de calculatoare
urmtorul:
<sys/types.h>
<sys/time.h>
<sys/socket.h>
<netinet/in.h>
<arpa/inet.h>
<errno.h>
<unistd.h>
<stdio.h>
<netdb.h>
<string.h>
<stdlib.h>
<fcntl.h>
/* eroarea returnata */
/* descriptor de socket */
void
Eroare (char *message) /* functie de afisare a erorilor */
{
if (errno == O)
perror (message);
el se
printf (message);
shutdown (sd, 2);
close (sd);
exit (errno);
}
int
main (int argc, char *argv[])
{
int bytes;
struct sockaddr_in server, client;
struct hostent *ip_addr;
char buffer[100];
fd_set citire, scriere;
struct timeval tv;
Multiplexarea
intrrilor /ieirilor
if (argc != 3)
{
case EINPROGRESS:
{
/* conectarea este in progres */
int value, len = sizeof (int);
FD_ZERO (&scriere);
FD_SET (sd, &scriere);
tv.tv_sec =TIMEOUT;
tv.tv_usec = O;
/* setam un timp de asteptare a conectarii */
if (!select (sd + 1, NULL, &scriere, NULL, &tv))
Eroare ("timpul de conectare a expirat!");
/*vedem ce eroare s-a returnat ... */
173
Atelier de programare n
174
reele
de calculatoare
default:
Eroare ("Eroare la conectare");
}
while (1)
{
FD_ZERD (&citire);
FD_SET (O, &citire);
FD_SET (sd, &citire);
tv.tv_sec = 5;
tv.tv_usec = O;
O)
FD_ZERO (&scriere);
FD_SET (sd, &scriere);
tv.tv_sec = TIMEOUT;
tv.tv_usec = O;
if (!select (sd + 1, NULL, &scriere, NULL, &tv))
Eroare ("Bufferul de scriere e plin ... ");
continue;
}
Multiplexarea
intrrilor /ieirilor
175
Primitiva getsockopt O a fost utilizat pentru a vedea ce eroare a survenit n cazul unui apel neblocant. Cu ajutorul acestei primitive se pot afla
i alte informaii uneori utile pentru programator. Un apel complementar este
setsockopt O care poate fi folosit pentru setarea unor parametri interni asociai socket-urilor.
O alt noutate care poate fi observat n sursa clientului este aceea c
utilizatorul, pentru a se conecta la server, nu va mai trebui s specifice adresa
IP a mainii pe care ruleaz acel server, ci adresa simbolic, n forma standard
dat de DNS (Domain Name Service).
Acest lucru se realizeaz prin intermediul funciei gethostbynam e ():
#include <netdb.h>
struct hostent *gethostbynam e(const char *name);
Funcia
struct hostent {
char
*h_name;
char
**h_aliases;
int
h_addrtype;
definiia:
Atelier de programare n
176
int
char
h_length;
**h_addr_list;
reele
de calculatoare
/* lungimea adresei */
/* lista de adrese IP */
10.4
Simulai situaiile
curent:
1. Fie un server TCP concurent la care se pot conecta simultan maxim
3 clieni. Serverul primete mesaje, din 3 n 3 minute, de la mcar doi
dintre clieni. Dac mesajele primite de la cei doi clieni nu coincid,
atunci serverul va trimite celor trei clieni mesajul "stop", dup care deconecteaz toi clienii. Dac mesajele coincid, serverul va atepta urm
toarele mesaje de la ali doi clieni ai si.
2. Dr. Jones era ntr-o expediie n jungla amazonian. Angajase 7 cluze
autohtone, dar nu prea avea ncredere n ele. De la fiecare calauz trebuia s primeasc, din 5 n 5 minute, cte un mesaj. Dac mesajul era
"pericol" nsemna c triburile potrivnice expediiei se pregteau de atac.
n aceast situaie, Dr. Jones trebuia s trimit fiecrei cluze ordinul
de a se ascunde n cocotieri. Dac mesajul era "linite", atunci totul
era (aparent) n ordine. Pentru a se asigura de exactitatea mesajelor
cluzelor sale, Dr. Jones trimitea mesajul de ascundere numai dac m
car 5 dintre cluze i indicau "pericol", altfel le ignora mesajele.
3.
Picard plecase ntr-o misiune de cercetare pe o planet neconducnd o mini-echip de cinci specialiti. Fiecare membru
al echipei avea ordinul ca la fiecare minut s trimit un mesaj ctre nava
Enterprise pentru a raporta datele culese. Echipajul navei avea misiunea de a prelucra aceste mesaje i de a le expedia cpitanului Picard
pentru ca acesta s aib o privire de ansamblu asupra ntregii expediii.
Unele mesaje puteau fi identice i atunci ele erau transmise cpitanului
o singur dat.
Cpitanul
cunoscut,
Multiplexarea
intrrilor /ieirilor
177
10.5
Rezolvri
Exerciiul
3.
Cpitanul
Picard
a
1
1
r
ll
a
I-
d
i.
Li
*/
#include
#include
#include
#include
#include
#include
#include
#include
<sys/types.h>
<sys/socket.h>
<sys/time.h>
<netinet/in.h>
<unistd.h>
<error.h>
<stdio.h>
<arpa/inet.h>
I* portul folosit */
#define PORT 8111
I* alte constante */
#define DEBUG 1
#define NR_MESAJE_JURNAL 10
#define NR_MEMBRI 5
Atelier de programare n
178
reele
de calculatoare
int i;
for (i
for (i
= O; i
mesaje [i]
}
}
int
add (char *msg)
char *aux;
int i;
aux = (char*) malloc (30 * sizeof (char));
strcpy (aux, msg);
for (i
{
Multiplexarea
intrrilor /ieirilor
179
/* programul */
int
main ()
{
-1)
II
== -1)
180
Atelier de programare n
reele
de calculatoare
case O:
/* eroare de citire */
case 1:
/* terminare transmisiu ne */
close (fd); /* inchidem conexiunea cu clientul *I
FD_CLR (fd, &actfds); /*scoatem si din multime */
printf
("\nS-a deconectat clientul cu descriptor ul %d."
"In acest moment, in jurnal am:\n", fd);
fflush (stdout);
for (contor
O;
contor < NR_MESAJE_JURNAL; contor++)
{
printf ("\n");
fflush (stdout);
break;
case 2:
printf ("Jurnal Picard e plin. Continut:\ n");
fflush (stdout);
for (contor
O;
contor < NR_MESAJE_JURNAL; contor++)
{
I* for *I
/* while */
181
Atelier de programare n
182
reele
de calculatoare
I* main */
char buffer[lOO ];
int bytes, i, first;
char *token;
int messageEx ist = O;
I* mesajul */
/* numarul de octeti cititi */
return 1;
count++;
printf ("count: %d\n", count);
fflush (stdout);
for (i
{
183
count
-1;
printf ("\n");
fflush (stdout);
return bytes;
}
Urmeaz
<sys/types.h>
<sys/socket.h>
<netinet/in.h>
<errno.h>
<unistd.h>
<stdio.h>
<stdlib.h>
<netdb.h>
<string.h>
Atelier de programare n
184
reele
de calculatoare
I* programul */
int
main (int argc, char *argv[])
{
int sd;
struct sockaddr_in server;
char buffer[100];
/* exista toate argumentele in linia de comanda? */
if (argc ! = 3)
{
/* stabilim portul */
port= atoi (argv[2]);
/* cream socketul */
if ((sd = socket (AF_INET, SDCK_STREAM, O))
-1)
{:
Multiplexarea
intrrilor /ieirilor
generateMessage (buffer);
printf ("Am generat: %s\n", buffer);
fflush (stdout);
if (write (sd, buffer, 100) < O)
{
sleep (2);
/* doarme 2 secunde */
int i;
count++;
if (count
== MESSAGE_COUNT)
185
1
1
Capitol ul 11
11.1
Sistem ul RPC
Scopul acestui capitol este de a arta cum se utilizeaz sistemul RPC (Remote
Procedure Call) pentru a construi aplicaii distribuite . ncepem prin a prezenta
cum lucreaz sistemul RPC. RPC permite unui client s execute proceduri pe
alte calculatoa re din reea. RPC face modelul client/ser ver mai puternic i
constituie un instrumen t de programa re mai simplu dect interfaa socket.
O aplicaie RPC simpl const dintr-un client i un server, serverul fiind pe
maina care execut procedura . Aplicaia client comunic cu procedura
de pe
calculator ul la distan transmind argument ele i recepionnd rezultatele.
Clientul i serverul se execut ca dou procese separate care pot fi pe calculatoare diferite din reea. Biblioteca RPC realizeaz comunica rea dintre aceste
dou procese. Procesele client i server comunic cu ajutorul a dou interfee
numite stub ("ciot"); vom avea deci un stub pentru client i altul pentru server.
Aceste interfee implementeaz protocolul RPC care specific cum sunt
construite i cum se prelucreaz{t mesajele emise ntre procesele client i server.
n figura de mai jos se poate face o comparaie ntre apelul local de procedur i apelul de procedur la distant. Figura 11.1, ca i alte figuri din
acest
capitol, sunt inspirate de cartea lui John Bloorner: Power Programrning with
RPC (O'Reilly, 1992) pe care o recomandm celor care vor s aprofundeze
mecanismul RPC.
Stub-urile se genereaz de obicei cu ajutorul comenzii rpcgen, dup care
se leag de programele client i server. Stub-urile conin funcii care translateaz apelurile locale de procedur intr-o secven de apeluri de funcii
RPC
de reea. Clientul apeleaz procedurile din stub-ul su prin care utilizeaz biblioteca RPC pentru a gsi procesul la distan i s-i transmit apoi cereri.
Procesul la distan "ascult" reeaua prin intermediul stub-ului su. Stub-uI
procedur vs
187
distan
apelul de
procedur
la
distan
Client
cal ling
procedura
ca lied
1m:ice!lme
Client
calling
proceduro
CIlent S.tub
m~twork
transport
Servei
called
prm;edure
Server Stub
network
transport
188
Atelier de programare n
reele
de calculatoare
ar
asociaz
obinuite
un flux de
funcia
urmtor:
#include <rpc/xdr.h>
#define BUFSIZE 400 I* lungimea zonei de memorie */
/* conversia unui intreg din format intern in format XDR *I
XDR *xdrm;
char buf[BUFSIZE];
int intreg;
1I
11.2
Cum
lucreaz
distan
189
sistemul RPC?
Oferirea unui serviciu n reea este diferit la sistemul RPC. Adresele clientului, serverului, numele serviciilor sunt pstrate la nivel simbolic. Un serviciu
este identificat prin portul la care este oferit i unde exist un daemon care
ateapt cererile de conectare. Un port reprezint un canal logic de comunicare. Portmapper-u l este un serviciu de reea care este responsabil cu asocierea
de servicii la diferite porturi; acest serviciu de mapare (asociere) a porturilor
este oferit la portul 111. Utiliznd portmapper-ul , numerele de port pentru
un anumit serviciu nu mai sunt fixe. Figura 11.2 descrie cei trei pai necesari
pentru ca un client s poat apela un server.
Figura 11.2:
Paii
s poat
apela un server
Porl:m~pper
~IVllf
Program
Atelier de programare n
190
clwmt
f)(O(Jfilm
iniiate
reele
de calculatoare
procedur
la
distan
Sem1r Malh/RI .
SIJllliee
daemon
11.'mnfnq
Clientul trimite o cerere n reea cu ajutorul unui apel callrpc O. Programul server ateapt mereu noi cereri, iar cnd o astfel de cerere este recepio
nat se invoc serviciul respectiv. O rutin dispatcher este de obicei folosit
atunci cnd un server furnizeaz mai multe servicii; dispatcher-ul identific
cererile specifice i apeleaz procedura corespunztoare. Se execut procedura
i se returneaz rspunsul care apoi este transmis prin reea la client. Clientul,
care n tot acest timp de dup momentul emiterii cererii a ateptat inactiv,
preia rspunsul i continu execuia.
11.3
client RPC
distan
191
funciile
- registerrpc O
nregistreaz o procedur spre a putea fi
- callrpc()
apeleaz o
procedur
la
distan
executat
(n prealabil
la
distan,
nregistrat),
- svc_run()
ruleaz un serviciu RPC.
Acest nivel este utilizat de majoritatea
aplicaiilor.
L-
>
a
1,
.;,
le
Procedurile la distan se vor include ntr-un program la distan, Un program la distan reprezint unitatea software care se va executa pe o main
aflat la distan. Fiecare program aflat la distan corespunde unui server,
putnd conine un set de una sau mai multe proceduri la distan sau date
globale. Procedurile pot partaja date comune. De notat faptul c argumentele
pasate procedurilor la distan trebuie s fie incapsulate ntr-o structur (similar cu struct din limbajul C) pentru a reduce numrul de argumente transmise procedurii.
Fiecrui program aflat la distan i se va asigna un identificator unic pe
32 de bii, iar fiecare procedur component (care va fi executat n cadrul
acelui program) este numerotat (indexat) secvenial de la 1 lan, unde n este
numrul maxim de proceduri ale acelui program.
Identificatorii de program n implementarea Sun RPC au fost divizai astfel:
00 00 00 00 - lF FF FF FF pentru
aplicaiile
ir
le
20 00 00 00 - 3F FF FF FF
destinai
programelor utilizatorilor;
192
Atelier de programare n
40 00 00 00 - 5F FF FF FF
reele
reprezint
l
I
de calculatoare
identificatori temporari;
predefinii
se pot enumera:
reea
NFS
lI
Il
!
Obinerea
distan
193
clientul RPC
s
V
e
l-
l.
~e
l-
e
a
tl
funciilor
serverului, a
L-
a
e
1r
~i
c
e
~i
e
a
n
J
Atelier de programare n
194
11.4
reele
de calculatoare
Exem plu
specificaie
RPC ntr-un
fiier
. x;
s conin
procedurile invocate;
realizeze apelurile
corespunztoare.
aplicaie
prin care
struct reques t
{
};
struct answer
{
program TRENURI
{
version VERSIUNE
{
}
}
Se
invoc
rpcgen -K 10 trenuri .X
Se
obin fiierele:
1
1
1
1
lrc
lrc
lrc
lrc
lrc
lrc
lrc
lrc
trenur i.h
trenur i _clnt.c
trenur i _svc.c
trenuri _xdr.c
1
I
s-l
distan
scriem este
195
urmtorul:
#include "trenuri.h"
#include "lib/lib.h"
#include "lib/app.h"
answer *
tren_1_svc (request * r, struct svc_req *srq)
{
~-
:e
FLECARI)
el se
{
return &a;
}
urmtorul:
<rpc/rpc.h>
<string.h>
<stdio.h>
"trenuri.h"
"lib/lib.h"
int
main (int argc, char *argv[])
{
request r;
I* cererea trimisa */
answer *a;
I* raspunsul primit */
CLIENT *el;
int opt, only_opt;
char server[300], *number = NULL;
if ((argc == 1) 11 (strcmp (argv[1], "--help") == O) 11
help (argv[O]);
Atelier de programare n
196
reele
de calculatoare
return O;
}
O;
opt
bzero (server, sizeof (server));
opt = process_ar g (argc, argv, &only_opt, &number, server);
/* creeaza procedura */
el= clnt_creat e (server, TRENURI, VERSIUNE, "tcp");
if (el == NULL)
{
Aceste programe se
compileaz
prin comenzile:
gcc server.c trenuri_sv c.c trenuri_xd r.c -L./ -lme -o server_tre nuri
gcc client.c trenuri_cl nt.c trenuri_xd r.c -L./ -lme -g -o trenuri
Mai multe
11.5
amnunte
Exerciii
li
distan
197
ar -r libme.a lib/*.o
gcc server .c trenuri _svc.c trenuri _xdr.c \
-L./ -lme -o server_ trenuri
gcc client .c trenur i_clnt. c trenuri _xdr.c \
-L./ -lme -g -o trenur i
instal l:
instal l
instal l
instal l
instal l
instal l
-m
-m
-m
-m
-m
0555
0555
0500
0555
0555
clean_ all:
make clean -C lib
rm -f *- *.o trenur i server_ trenuri trenuri X libme.a
clean:
make clean -C lib
rm -f *- *.o
Ca
exerciiu, realizai
mai nti propriu l Makefi le. Apoi ncercai s trano aplkaie client/s erver propus n cadrul capitolelor precede nte utiliznd mecani smul RPC.
scriei
cu
.J
.j
~ I
l l
Capitolul 12
12.1
12.1.1
Schi
r-
de rezolvare
l
I
I
~
~~~~~~~~~~~~~~~~~~
199
~~~~~~~~~~~~~~~
iei
m
de
student
grupa
MODIFY cu sintaxa:
,re
un
Descriere parametri:
;at
~m
student
grupa
nota
absenta
saptamana
~Cl
de
cu
200
DELETE va terge din baza de date fie grupa specificat, fie numai
studentul din grupa specificat. Dac grupa sau studentul nu exist, se
va returna un mesaj de eroare.
Comanda funcioneaz numai pe baza autentificrii.
12.2
RESULT out;
MYSQL mysql,*soc k;
MYSQL_RES *res;
l
I
l -
1~~~~~~~~~~-U_t_il_iz_a_re_a~b1_b_li_o_te_c_ii_JJ---'-yS--'-Q_L__~~~~~~~~-20_1
o.ai
se
MYSQL_ROW row;
unsigned int num_fields;
unsigned int i,j;
unsigned long *lengths;
char qbuf[200], *buff;
out.code = OK;
out.lines = O;
/* initializare */
mysql_init(&mysql);
/* conectare la serverul MySQL */
if (!(sock = mysql_real_connect(&mysql,NULL,0,0,"bd",0,NULL,0) ))
{
nai
ac
Lde,
}
rele
/* trimitere interogare */
if (mysql_query (sock, qbuf))
{
Atelier de programare n
202
reele
de calculatoare
O;
i =
num_fields = mysql_num_fields(res);
while (( row= mysql_fetch_row(res)))
{
strcat(out.result_row[i], "[");
sprintf(buff,"%.*s",
(int) lengths[j], row[j] ? row[j]
strcat(out.result_row[i], buff);
strcat(out.result_row[i], "]");
"NULL");
printf("\n");
i++;
printf("linia %d
%s \n", i,out.result_row[i-1]);
out.lines = i;
mysql_free_result(res);
mysql_close(sock);
return out;
}
/* autentificarea */
RESULT autent (char *login, char *passwd)
{
RESULT out;
MYSQL mysql,*sock;
MYSQL_RES *res;
char qbuf[200];
out.code = OK;
out.lines = O;
mysql_init(&mysq l);
if (!(sock = mysql_real_connec t(&mysql,NULL,0, 0,"bd",0,NULL,O)) )
{
if (!(res=mysql_sto re_result(sock)))
{
if ( mysql_num_rows(r es)
out.code = ERR_LOGIN;
mysql_free_resu lt(res);
mysql_close(sock );
return out;
O)
RESULT out;
MYSQL mysql,*sock;
char qbuf[200];
out.code = OK;
out.lines = O;
mysql_init(&mysq l);
i f (!(sock = mysql_real_connec t(&mysql,NULL,0, 0,"bd",O,NULL,O) ))
{
203
1
j
Atelier de programare n
204
reele
de calculatoare
perror("");
out.code = ERR_DB_CONNECT;
exit(1);
}
mysql_close(sock);
return out;
}
RESULT out;
MYSQL mysql,*sock;
char qbuf[200];
int k;
out.code = OK;
out.lines = O;
mysql_init(&mysql);
if (!(sock = mysql_real_connect(&mysql, NULL,O,O,"bd",0,NULL,O)) )
{
==
O)
205
mysql_close(sock );
return out;
}
MYSQL mysql,*sock;
MYSQL_RES *res;
char qbuf[200];
int g=O;
mysql_init(&mysq l);
if (!(sock = mysql_real_connec t(&mysql,NULL,0, 0, 11 bd 11 ,0,NULL,O)))
{
if ( student == NULL )
sprintf(qbuf,"SELE CT * FROM grupe WHERE grupa='%s'
AND profesor='%s' 11 , grupa, profesor);
if ( (student != NULL) && (profesor == NULL) )
sprintf (qbuf, "SELECT * FROM studenti "
11 WHERE grupa='%s' AND nume='%s' 11
,
grupa, student);
if ( (student !=NULL) && (profesor!=NULL)
sprintf(qbuf,"SELE CT * FROM note WHERE grupa='%s'
11 AND student='%s' AND 11
"profesor='%s'", grupa, student, profesor);
if(mysql_query(so ck,qbuf))
{
11
Atelier de programare n
206
reele
de calculatoare
exit(1);
}
fprintf(std err,
"Couldn't get result from %s\n",mys ql_error(so ck));
exit(1);
}
MYSQL mysql,*soc k;
MYSQL_RES *res;
char qbuf[200];
int g = O;
mysql_init( &mysql);
if (!(sock = mysql_real_ connect(&m ysql,NULL ,0,0,"bd",0, NULL,0)))
{
if ( student == NULL )
sprintf(qbu f,"SELECT * FROM note WHERE grupa='%s' ", grupa);
el se
sprintf(qbu f,"SELECT * FROM note WHERE student='% s'
AND grupa='%s '",student, grupa);
if(mysql_q uery(sock,q buf))
{
if ( mysql_num_rows(res) > O )
g = 1;
mysql_fre e_result(re s);
mysql_clos e{sock);
return g;
}
MYSQL mysql,*soc k;
MYSQL_RES *res;
char qbuf[200];
int g = O;
mysql_init( &mysql);
if (!(sock = mysql_real_ connect(&m ysql,NULL ,0,0,"bd",0, NULL,0)))
{
if ( mysql_num_rows(res) > O )
g = 1;
mysql_fre e_result(re s);
mysql_clos e(sock);
return g;
}
207
Atelier de programare n
208
reele
de calculatoare
/* stergere grupa */
RESULT delete_grupa (char *grupa, char *profesor)
{
RESULT out;
MYSQL mysql,*sock;
char qbuf1[200], qbuf2[200];
out.code = OK;
out.lines = O;
mysql_init(&m ysql);
if (!(sock = mysql_real_co nnect(&mysql, NULL,0,0,"bd ",0,NULL,O)))
{
if ( cauta_student( grupa,NULL) == O )
{
mysql_close( sock);
return out;
}
RESULT out;
MYSQL mysql,*sock;
209
char qbuf[200];
out.code = OK;
out.lines = O;
mysql_init(&mysql);
if (!(sock = mysql_real_connect(&mysql,NULL,O,O,"bd 11 ,0,NULL,O)))
{
11
fprintf(stderr,
11 Query failed (%s)\n 11 , mysql_error(sock));
exit(1);
}
if ( cauta_student(grupa, student) == O )
{
fprintf(stderr,
"Query failed (%s)\n 11 , mysql_error(sock));
exit(1);
}
}
mysql_close(sock);
return out;
}
I modificare informatii /
RESULT modi (char stud, char grupa,
int nota, int abs, int sapt, char prof)
{
RESULT out;
MYSQL mysql,sock;
char qbuf1[200], qbuf2[200];
out.code = OK;
210
Atelier de programare n
reele
de calculatoare
out.lines = O;
mysql_init(&mysql);
i f ( ! (sock = mysql_real~connect (&mysql ,NULL,O ,O, 11 bd'",O ,NULL,O)))
{
'
fprintf(stderr, 11 Couldn't connect to engine!\n%s\n\n 11 ,
mysql_error(&mysql));
perror( 1111 ) ;
out.code = ERR_DB_CONNECT;
exit(1);
}
fprintf(stderr,
exit(1);
11
mysql_close(sock);
return out;
}
char *buff;
MYSQL mysql,*sock;
MYSQL_RES *res;
MYSQL_ROW row;
unsigned long *lengths;
char qbuf[200];
mysql_init(&mysql);
if (!(sock = mysql_real_connect(&mysql,NULL,0,0, 11 bd 11 ,0,NULL,O)))
{
1
I
211
if (!(res=mysql_store_result(sock)))
{
buff = (char*)malloc(30);
lengths = mysql_fetch_lengths(res);
sprintf(buff,"%.*s",
(int) lengths[O], row[O] ? row[O]
"NULL");
mysql_free_result(res);
mysql_close(sock);
return buff;
}
Funciile
fiierele
sql.h
#include "definitii.h"
#include "errorcodes.h"
/* prototipuri ale functiilor utilizate in dialogul
cu serverul MySQL */
RESULT selecteaza(char *profesor, char *grupa,
char *student, int arg);
RESULT autent( char *login, char *passwd);
RESULT nou_grupa(char *grupa, char *profesor);
RESULT nou(char *grupa, char* stundent, char *profesor);
int cauta(char *grupa, char *student, char *profesor);
int cauta_prof(char *profesor);
RESULT delete_grupa(char *grupa, char *profesor);
RESULT delete(char *student, char *grupa, char *profesor);
RESULT modi(char *student, char *grupa,
int nota, int absenta, int sapt, char *profesor);
char* id(char *prof);
212
Atelier de programare n
reele
de calculatoare
errorcodes. h
/* codurile de eroare returnate de serverul MySQL */
#ifndef errorcodes_h
#define errorcodes_h
#include "definitii.h"
static const ERR_CODE OK
{O, "OK"};
static const ERR_CODE ERR_NSE
{1, "No such entry in table" };
static const ERR_CODE ERR_SYNTAX
{2, "Incorrect syntax"};
static const ERR_CODE ERR_ARG =
{3, "Invalid nurnber of argurnents"};
static const ERR_CODE ERR_FOUND =
{4, "Data already exists"};
static const ERR_CODE ERR_DB_CONNECT
{5, "Error database connection"};
static const ERR_CODE ERR_QUERY =
{6, "Error ~n query co!Illiland"};
static const ERR_CODE ERR_RESULT =
{7, "Error in getting the result"};
static const ERR_CODE ERR_NOTFOUND =
{8, "Data does not exist"};
static const ERR_CODE ERR_COMMAND
{9, "Co!Illiland does not exist"};
static const ERR_CODE ERR_LOGIN =
{10, "Login and password failed"};
static const ERR_CODE ERR_ACCESS =
{11, "Access denied"};
static const ERR_CODE ERR_INCORECT =
{12, "Incorrect data"};
#endif
definitii.h
/* definitii de tipuri utilizate in server */
#ifndef definitii_h
#define _definitii_h
typedef struct st_error_codes {
int value;
char *message;
} ERR_CODE;
213
Capitolul 13
Biblioteca ncurses
Acest capitol prezint pe scurt biblioteca ncurses i cum
se utilizeaz funciile acestei biblioteci prin prezentarea
unei aplicaii client/server.
13.1
Descriere
general
13.2
Prezentarea
funciilor
bibliotecii ncurses
l
i
Biblioteca ncurses
215
stng
a chenarului feres-
Atelier de programare n
216
reele
de calculatoare
Dac
urmtoarele
valori
217
Biblioteca ncurses
13.3
Enunul
unei probleme
"S
13.3.1
furnizeaz
lista utilizatorilor
existeni
pe
maina
Rezolvarea problemei
informaiile
ncurses.
<stdio.h>
<string.h>
<stdlib.h>
<ctype.h>
<termios.h>
<curses.h>
<utmp.h>
<paths.h>
<time.h>
<unistd.h>
<signal.h>
<netdb.h>
<sys/socket.h>
<sys/stat.h>
<arpa/inet.h>
"ftop.h"
I* Sort
#define
#define
#define
#define
list by ... */
USER_SORT
HDST_SORT
IDLE_TIME_SORT
LDGIN_TIME_SORT
_ /* Sorting order. */
#define SORT_ASCEND
#define SORT_DESCEND
1
2
3
4
O
1
I* Prototypes */
218
Atelier de programare n
reele
de calculatoare
int key, i;
char *delay_c =(char*) malloc (COLS * sizeof (char));
struct termios original, raw;
char any;
delay = 5;
alarm (delay);
signal (SIGALRM, update);
tcgetattr (O, &original) ;
cfmakeraw (&raw);
initscr O;
cbreak O;
noecho ();
nonl ();
intrflush (stdscr, FALSE);
stat_win = newwin (2, COLS, O, O);
wattrset (stat_win, A_BOLD);
input_win = newwin (1, COLS, 2, O);
keypad (input_win , TRUE);
head_win = newwin (1, COLS, 3, O);
wattrset (head_win, A_REVERSE);
wprintw (head_win, "%-10s %-7s %-24s %8s %-15s %4s\n",
"USER" "LINE" "FROM" "IDLE" "LOGIN-TIME", "MESG");
wattrset' (head_wln, A_NORMAL); '
wrefresh (head_win) ;
info_pad = newpad (MAX_USER_COUNT, COLS);
DATA = NULL;
user_count = O;
sort_type = USER_SORT;
sort_order = SORT_ASCEND;
info_pad_p os = O;
update (O);
key = wgetch (input_win );
while (key != 'q')
{
switch (key)
{
Biblioteca ncurses
case '?':
case 'h':
alarm (O);
endwin O;
command_list O ;
fflush (stdout);
tcsetattr (O, TCSANOW, &raw);
read (O, &any, 1);
tcsetattr (O, TCSANOW, &original);
doupdate O;
update (O);
break;
case 's':
alarm (O);
wprintw (input_win,
"Delay between updates (O - no updating): ");
echo ();
wgetstr (input_win, delay_c);
wclear (input_win);
noecho O;
wrefresh (input_win);
if (strlen (delay_c) != O)
{
i = O;
while (i < strlen (delay_c) && isdigit (delay_c[i]))
i++
beep O;
wattrset (input_win, A_REVERSE);
wprintw (input_win, "Invalid input!");
wrefresh (input_win);
sleep (2);
wattrset (input_win, A_NORMAL);
wclear (input_win);
wrefresh (input_win);
}
el se
delay =atol (delay_c);
}
update (O);
break;
case '> ' :
case 'r':
update (O);
break;
I* Scrolling commands. */
case KEY_UP:
if (info_pad_pos > O)
{
info_pad_pos--;
prefresh (info_pad, info_pad_pos,
O, 4, O, LINES, COLS);
}
el se
beep O;
219
220
Atelier de programare n
reele
de calculatoare
break;
case KEY_DOWN:
if (user_coun t - info_pad_p os > LINES - 4)
{
info_pad_p os++;
prefresh (info_pad, info_pad_p os,
O, 4, O, LINES, COLS);
el se
beep O;
break;
case KEY_PPAGE:
if (info_pad_p os > O)
{
info_pad_p os -= LINES - 4;
if (info_pad_p os < O)
info_pad_p os = O;
prefresh (info_pad, info_pad_p os,
O, 4, O, LINES, COLS);
el se
beep O;
break;
case KEY_NPAGE:
if (user_coun t - info_pad_p os > LINES - 4)
{
info_pad_p os += LINES - 4;
if (user_coun t - info_pad_p os < LINES - 4)
info_pad_p os = user_count - (LINES - 4);
prefresh (info_pad, info_pad_p os,
O, 4, O, LINES, COLS);
el se
beep O;
break;
case KEY_HOME:
if (info_pad_p os > O)
{
info_pad_p os = O;
prefresh (info_pad, info_pad_p os,
O, 4, O, LINES, COLS);
el se
beep O;
break;
case KEY_END:
if (user_coun t - info_pad_p os > LINES - 4)
{
el se
beep O;
break;
Biblioteca ncurses
I* Sorting commands. */
case 'u':
sort_type = USER_SORT;
sort_order = SORT_ASCEND;
sort_list () ;
update_screen ();
break;
case 'U':
sort_type = USER_SORT;
sort_order = SORT_DESCEND;
sort_list () ;
update_screen ();
break;
case 'f':
sort_type = HOST_SORT;
sort_order = SORT_ASCEND;
sort_list () ;
update_screen ();
break;
case 'F':
sort_type = HOST_SORT;
sort_order = SORT_DESCEND;
sort_list ();
update_screen ();
break;
case 'i':
sort_type = IDLE_TIME_SORT;
sort_order = SORT_ASCEND;
sort_list () ;
update_screen ();
break;
case 'I':
sort_type = IDLE_TIME_SORT;
sort_order = SORT_DESCEND;
sort_list () ;
update_screen ();
break;
case 'l':
sort_type = LOGIN_TIME_SORT;
sort_order = SORT_ASCEND;
sort_list () ;
update_screen ();
break;
case 'L':
sort_type = LOGIN_TIME_SORT;
sort_order = SORT_DESCEND;
sort_list () ;
update_screen ();
break;
default:
beep ();
wattrset (input_win, A_REVERSE);
wprintw (input_win,
"Unknown command '%c' -- hit 'h' for help", key);
wrefresh (input_win);
sleep (1);
wattrset (input_win, A_NORMAL);
221
Atelier de programare n
222
reele
de calculatoare
wclear (input_win);
wrefresh (input_win);
}
key
= wgetch (input_win);
endwin ();
exit (EXIT_SUCCESS);
}
int
ftop_cmp (const void *a, const void *b)
{
int result;
switch (sort_type)
{
case USER_SORT:
result = strcasecmp
((*((struct ftop_data **) a))->ft_user,
(*((struct ftop_data **) b))->ft_user);
break;
case HOST_SORT:
result = strcasecmp
((*((struct ftop_data **) a))->ft_host,
(*((struct ftop_data **) b))->ft_host);
break;
case IDLE_TIME_SORT:
if ((*((struct ftop_data **) a))->ft_idle_time _t
< (*((struct ftop_data **) b))->ft_idle_time _t)
result = -1;
el se
result = (*((struct ftop_data **) a))->ft_idle_time _t
> (*((struct ftop_data **) b))->ft_idle_time _t;
break;
case LOGIN_TIME_SORT:
if ((*((struct ftop_data **) a))->ft_login_tim e_t
< (*((struct ftop_data **) b))->ft_login_tim e_t)
result = -1;
el se
result = (*((struct ftop_data **) a))->ft_login_tim e_t
> (*((struct ftop_data **) b))->ft_login_tim e_t;
}
return (sort_order
== SORT_ASCEND)
? result : -result;
void
sort_list (void)
{
if (DATA == NULL)
return;
qsort ((void *) DATA, user_count,
sizeof (struct ftop_data *), ftop_cmp);
char *
format_idle (time_t idle)
{
Bibliotec a ncurses
int d, h, m, s;
char sh[3], sm[3], ss[3];
char *res = malloc (8 * sizeof (char));
idle I 3600 I 24;
idle I 3600;
id le % 3600 I 60;
idle % 3600 % 60;
i f (d > O)
d
h
m
s
i f (h > O)
{
char *
format_ time (time_t time)
{
223
Atelier de programare n
224
reele
de calculatoare
void
update_data (void)
{
DATA = NULL;
user_count = O;
/* Gather data from utmp file. */
setutent O;
while ((utmp_entry = getutent ()) != NULL)
{
if (utmp_entry->ut_type != USER_PROCESS)
continue;
user_count++;
DATA = (struct ftop_data **)
realloc (DATA, user_count *
sizeof (struct ftop_data *));
DATA[user_count - 1] =
(struct ftop_data *) malloc (sizeof (struct ftop_data));
data= DATA[user_count - 1];
strcpy (data->ft_user, utmp_entry->ut_user);
strcpy (data->ft_tty, utmp_entry->ut_line);
strcpy (data->ft_host, utmp_entry->ut_host);
strcpy (terminal, _PATH_DEV);
strcat (terminal, utmp_entry->ut_line);
stat (terminal, &stat_entry);
data->ft_idle_time_t = time (NULL) - stat_entry.st_atime;
idle_time = format_idle (data->ft_idle_time_t);
strcpy (data->ft_idle_time_c, idle_time);
free (idle_time);
data->ft_login_time_t = utmp_entry->ut_tv.tv_sec;
login_time = format_time (data->ft_login_time_t);
strcpy (data->ft_login_time_c, login_time);
free (login_time);
data->ft_mesg_stat = (stat_entry.st_mode & S_IWGRP) ? '+'
endutent O;
I* Sort the data according to current sorting order. */
sort_list () ;
}
void
update_screen (void)
{
' - '.
'
Biblioteca ncurses
time_t daytime;
int i;
wclear (stat_win);
wclear (info_pad);
gethostname (host_name, UT_HOSTSIZE);
daytime = time (NULL);
/* ctime ()'s output ends in '\n', which we don't want. */
strcpy (local_time, strtok (ctime (&daytime), "\n"));
mvwprintw (stat_win, O, O, "Host: %s", host_name);
mvwprintw (stat_win, 1, O, "%s, %d user(s)",
local_time, user_count);
wrefresh (stat_win);
for (i = O; i < user_count; i++)
{
mvwprintw (info_pad, i, O,
"%-10.10s %-7s %-24.24s %8s %15s
%c",
DATA[i]->ft_user,
DATA[i]->ft_tty,
DATA[i]->ft_host,
DATA[i]->ft_idle_time_c,
DATA[i]->ft_login_time_c, DATA[i]->ft_mesg_stat);
void
update (int signum)
I* Takes an int as an argument to match
the signal-handler prototype. */
{
update_data () ;
if (info_pad_pos > O &&
user_count - info_pad_pos < LINES - 4)
info_pad_pos = user_count - (LINES - 4);
if (info_pad_pos < O)
info_pad_pos = O;
update_screen ();
alarm (delay);
}
void
command_list (void)
{
225
Atelier de programare n
226
reele
de calculatoare
PgDown
Home
End
space, r
h, ?
antet:
ftop.h
#ifndef _FTOP _H
#define _FTOP_H
#include <utmp.h>
#include <time.h>
char ft_user[UT_NAMESIZE];
char ft_tty[UT_L INESIZE];
char ft_host[UT_HOSTSIZE];
time_t ft_idle_tim e_t; /* For sorting by idle time. */
char ft_idle_tim e_c[9]; /* 'HH:MM:SS' + '\O' */
time_t ft_login_ti me_t; /* For sorting by login time. *I
char ft_login_ti me_c[16]; /* 'MMM DD HH:MM:SS' + '\0' */
char ft_mesg_st at; /* '+' or '-' */
};
#endif /* _FTOP_H */
Capitolul 14
Mediul Glade
prezint pe scurt maniera de dezvoltare de
n reea folosind mediul Glade, pornind de la
rezolvarea unei probleme. Interfaa grafic se realizeaz
utiliznd biblioteca Gtk.
Capitolul
aplicaii
Formularea
14.1
rezolvarea problemei
dac
studeni, s
14.2
Conceperea
crypt().
interfeei
14.2.1
funcia
n Gtk, folo-
callbacks.c
interface.c
Atelier de programare n
228
reele
de calculatoare
main.c
support.c
caset
funcia
informaii
despre un student
fereastr folosit
funcia
caset
funcia
de dialog utilizat la
create_adauga().
adugarea
unui student
Fiierul
coninnd funcii
pentru
Mediul Glade
Figura 14.1: Proiectarea
Cteva dintre
fiierele
interfeei
support.h
/* DO NOT EDIT THIS FILE - it is generated by Glade. */
#include <gnome.h>
/* Public Functions. */
/*
* Call
229
230
Atelier de programare n
reele
de calculatoare
*I
GtkWidget*
lookup_widget (GtkWidget
const gchar
*widget,
*widget_name);
*filena.me);
support.c
I*
* DO NOT EDIT THIS FILE - it is generated by Glade.
*I
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include
#include
#include
#include
#include
<sys/types.h>
<sys/stat.h>
<unistd.h>
<string.h>
<gnome.h>
#include "support.h"
/* This is an internally used function to create pixmaps. */
static GtkWidget* create_dU111I11y_pixmap
*widget,
(GtkWidget
gnome_pixmap);
gboolean
GtkWidget*
lookup_widget (GtkWidget
const gchar
*Widget,
*widget_name)
Mediul Glade
for (;;)
{
if (GTK_IS_MENU (widget))
gtk_menu_get_attach_widget (GTK_MENU (widget));
parent
el se
widget->parent;
parent
if (parent == NULL)
break;
widget = parent;
}
found_widget
(GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget),
widget_name);
if (!found_widget)
g_warning ("Widget not found: %s", widget_name);
return found_widget;
}
" c None",
/* pixels */
1f
li
li
li
};
GdkColormap *colormap;
GdkPixmap *gdkpixmap;
GdkBitmap *mask;
GtkWidget *pixmap;
if (gnome_pixmap)
{
231
232
Atelier de programare n
reele
de calculatoare
NULL, dummy_pixmap_xpm);
if (gdkpixmap == NULL)
g_error ("Couldn't create replacement pixmap,");
pixmap= gtk_pixmap_new (gdkpixmap, mask);
gdk_pixmap_u nref (gdkpixmap);
gdk_bitmap_u nref (mask);
return pixmap;
}
GtkWidget *pixmap;
GdkColormap *colormap;
GdkPixmap *gdkpixmap;
GdkBitmap *mask;
gchar *pathname;
if (!filename I I !filename[O])
return create_dummy_pixmap (widget, gnome_pixmap);
pathname = gnome_pixmap _file (filename);
if ( !pathname)
{
if (gnome_pixmap)
{
Mediul Glade
g_free (pathname);
pixmap= gtk_pixmap_new (gdkpixmap, mask);
gdk_pixmap_unref (gdkpixmap);
gdk_bitmap_unref (mask);
return pixmap;
}
Gdklmliblmage *image;
gchar *pathname;
pathname = gnome_pixmap_file (filename);
i f ( ! pathname)
{
Fereastra
principal
Figura 14.2:
Login
interfeei
Interfaa
Date stude'nti
Student:
Crupa4
PIU
Nota:
Nr prezente:
233
Bibliografie
[1] D. Corner, Internetworking with TCP/IP, Vol. 1: Principles, Protocols,
and Architecture, Second Edition, Prentice Hall, New Jersey, 1991.
[2] D. Corner, D. Stevens, Internetworking with TCP/IP, Vol. 3: ClientServer Programming and Applications, Prentice Hall, New Jersey, 1993.
[3] I. Ignat et al., Sistemul de operare UNIX. Gestionarea fiierelor, Editura
Microinformatica, Cluj-Napoca, 1992.
[4] I. Ignat, A. Kacso, UNIX - Gestiunea proceselor, Editura
Napoca, 1995.
Albastr,
Cluj-
Glosar
Antete
dirent.h, 41
error.h, 68
grp.h, 43
mysql.h, 200
ncurses.h, 214
netdb.h, 176
netinet/in.h, 137
pwd.h, 42
rpc/xdr.h, 188
signal.h, 71
stdio.h, 31
sys/socket.h, 123
sys/stat.h, 38
sys/time.h, 161
sys/types.h, 54
unistd.h, 38
utmp.h, 44
Asincronism, 121, 168
Biblioteci, 37
/lib, 17
crypt, 227
Gtk, 227
mysqlclient, 200
ncurses, 214
rpclib, 193
Comenzi, 13
bash, 27
bg, 57
cat, 23
cd, 17
chfn, 55
chmod, 21
cp, 22
cut, 25, 27
fg, 57
file, 23
find, 29
finger, 26, 55, 97
gcc, 37, 193, 196
gdb, 37
grep, 27
halt, 70
head, 23
jobs, 57
kill, 70, 72
killall, 72
last, 44
less, 23, 73
ln, 22
ls, 16, 17, 48, 63
ltrace, 37
make, 144, 196, 228
man, 17, 18, 38
mkdir, 17
mkfifo, 91
more, 23
236
Atelier de programare n
mv, 22
nice, 55
nohup, 57, 69
ps, 56, 64, 145
pwd, 17
reboot, 70
rm, 22
rmdir, 17
rpcgen, 186, 194
set, 56
shutdown, 70
sort, 25, 27
stat, 24
strace, 37
tac, 23, 35
tail, 23, 76
top, 57, 217
trap, 72
uniq, 25
w, 26
wc, 23
who, 26, 44
Constante
AF _INET, 124
AF _UNIX, 124
EOF, 31
INADDR_ANY, 134
INADDR_NONE, 138
PF _INET, 124
PF _UNIX, 124
SIG_DFL, 72
SIG_ERR, 72
SIG_IGN, 72
SOCK_DGRAM, 124, 150
SOCK_RAW, 124
SOCK_STREAM , 124, 150
reele
de calculatoare
XDR_DECODE, 188
XDR_ENCODE, 188
Conversia datelor, 137
big endian, 137
gethostbyname(), 175
htonl(), 137
htons(), 137
inet_addr(), 138
inet_aton(), 138
inet _ ntoa(), 138
little endian, 137
ntohl(), 137
ntohs(), 137
Datagrame, 150
Directoare, 16, 17, 41
Exerciii,
14, 42
Descriptori, 31
I-nod, 16
Permisiuni, 19, 38
Fiiere sistem, 16, 42
/dev/null, 16, 57
/dev/tty, 54
/etc/group, 16, 43
/etc/hosts, 17
/etc/passwd, 16, 27, 42, 55
/etc/protocols, 16
/etc/services, 16, 73, 134
/etc/shadow, 27
/var/log/wtmp, 44
/var/run/utmp, 44
Modelul client/server, 131, 150, 168,
198, 214, 227
Glosar
Multiplexare, 160, 177
Pipe, 15, 70, 77, 94, 96
Port, 134
Primitive
abort(), 73
accept(), 123, 132, 134, 167, 168
access(), 38
alarm(), 70, 74
bind(), 123, 131, 133
chdir(), 42
chmod(), 38
chown(), 38
close(), 31, 34, 47, 78, 123, 132,
135
connect(), 123, 136
creat(), 31, 33, 78
<lup(), 93
dup2(), 94
exit(), 55, 61
fcntl(), 168
fork(), 58, 68, 78, 145
getegid(), 61
geteuid(), 61
getgid(), 60
getpeername(), 138
getpgrp(), 60
getpid(), 60
getppid(), 60
getsockname(), 138
getsockopt(), 175
getuid(), 60
ioctl(), 168
kill(), 72
link(), 38
listen(), 123, 132, 134
lseek(), 31, 33, 78, 93
237
mkdir(), 42
mkfifo(), 80
mknod(), 81
open(), 31, 32, 47, 78, 80, 93
pause(), 72
pipe(), 77, 128
raise(), 72
read(), 31, 33, 47, 78, 123, 135,
168
receive(), 123
recv(), 135
recvfrom(), 150, 168
rename(), 38
rmdir(), 42
select(), 160, 161
send(), 123, 135
sendto(), 150
setgid(), 61
setpgrp(), 60
setsockopt(), 175
setuid(), 61
shutdown(), 123, 132, 135
signal(), 71
sleep(), 73, 76, 162
socket(), 123", 131, 133, 150
socketpair(), 128
stat(), 38
symlink(), 38
unlink(), 80
wait(), 60, 145
waitpid(), 60
write(), 31, 33, 47, 78, 123, 135
Proces, 34, 54, 72, 96
Daemon, 17, 55, 134, 156
EGID, 55
EUID, 55
238
Atelier de programare n
GID, 27, 55
init, 54
lider, 54
PID, 54, 72
PPID, 54
UID, 26, 55
zombie, 55, 60, 145
Protocol
ARP, 121
HTTP, 134
ICMP, 121
IP, 121
RARP, 121
SMTP, 134
TCP, 121, 124, 131
TCP /IP, 121, 131
UDP, 121, 124, 131, 150
14, 47, 64, 83, 98, 145,
156, 177
RPC, 186
callrpc(), 190-192
dispatcher, 190
portmapper, 189
program la distan, 191
registerrpc(), 191
rpcgen, 192
stub, 186
svc_run(), 191
XDR, 187, 192
xdrmem_create(), 188
Rezolvri,
Semnal, 69, 72
SIGABRT, 73
SIGALRM, 70, 74
SIGBUS, 70
SIGCHLD, 70, 145
reele
de calculatoare
SIGFPE, 70
SIGHUP, 69.
SIGILL', 70
SIGINT, 70
SIGIO, 70
SIGKILL, 70
SIGPIPE, 70, 146
SIGQUIT, 70
SIGSEGV, 70, 76
SIGTERM, 70
SIGURG, 70
SIGUSRl, 70
SIGUSR2, 70, 73
Server
concurent, 145, 163, 168, 177
iterativ, 131, 139, 150, 151
Socket, 15, 122, 123, 128, 131, 168
getpeername(), 138
getsockname(), 138
neblocant, 168
socketpair(), 128
Tipuri de date
DIR, 41
dirent, 41
fd_set, 160
FILE, 31
hostent, 175
in_addr, 133
passwd, 43
pid_t, 54
sockaddr, 133
sockaddr _ in, 133
timeval, 161
utmp, 44
Tratarea erorilor, 48, 68, 176
La Editura POLIROM
au
aprut