|
TCP/IP komunikácia
(server/klient) v OS Linux
Úvod
Resolve Domain Name
Klávesnica v konzole
TCP/IP Client
TCP/IP Server
Manuálové stránky
Download
Záver
Zdroje
Úvod
Zabezpečiť komunikáciu v linuxáckej homogénnej sieti nie je až taký
problém, ako by sa žiakom mohol javiť. Z hľadiska programátorského je
takáto komunikácia ešte jednoduchšia, než v sieti na báze M$ Windows. Na
úvod však treba uviesť a objasniť niekoľko základných pojmov (ako TCP,
IP, socket a i.).
IP
Protokol IP (Internet Protokol) je komunikačný protokol, na ktorom je
postavený napríklad Internet. IP protokol zaisťuje komunikáciu dvoch
počítačov. Komunikácia prebieha výmenou tak zvaných IP paketov. IP paket
obsahuje hlavičku a údaje, ktoré prenáša. Tieto údaje sa prenášajú na
sieťové rozhrania s danou IP adresou. IP adresa je súčasťou hlavičky IP
paketu. IP adresa (vo verzii protokolu IPv4) má 4 byte. Je běžné
používať na Internete ako adresu nie 4 byteové číslo, ale nejaký textový
reťazec, napríklad www.linux.sk. Takýto textový reťazec sa lepšie
pamätá. Napríklad http://147.175.66.133 by sa asi ťažko pamätal. Dôvod,
prečo boli zavedené tieto textové reťazce, doménové mená (Domain Name)
je teda čisto praktický. Ak chceme komunikovať, musíme poznať IP
adresu. Bežne sa reťazce doménových mien prekladajú na IP adresy pomocou
DNS serverov (Domain Name Server), v časti Resolve Domain Name je
jednoduchý program, ktorý by to mohol (za pomoci súboru /etc/hosts
alebo DNS servera) zvládnuť.
TCP
Protokol TCP (Transmision Control Protocol) je dnes asi
najpoužívanejší. Jedná sa o tak zvanú spojovú službu. Znamená to, že
pred vlastnou komunikáciou sa uskutoční (naviaže) spojenie. Všetky
odoslané údaje sa potvrdzujú a na koniec je nutné spojenie ukončit
(uzavrieť). TCP paket obsahuje svoju hlavičku a vlastné údaje, ktoré
prenáša. Súčasťou TCP hlavičky je tak zvaný port. Jedná sa o 2 byte-ové
číslo. Každá aplikácia, ktorá komunikuje pomocou TCP má pridelený svoj v
rámci počítača jednoznačný port. Ak povieme, že IP protokol zaisťuje
komunikáciu dvoch počítačov, tak TCP protokol zaisťuje komunikáciu dvoch
aplikácií (procesov) na týchto počítačoch. TCP port možno teda považovať
za jednoznačnú "adresu" aplikácie na počítači. Preto pri TCP spojení
budeme zadávať vždy IP adresu (alebo doménové meno) a TCP port. Budeme
teda určovať, s akým počítačom a s akou aplikáciou (procesom) na ňom
chceme komunikovať. Komunikácia pomocou TCP/IP prebieha na princípe
klient - server. Server je program, ktorý čaká na pripojenie. Klient je
program, který spojenie naväzuje.
TCP/IP komunikácia
Od okamihu, keď používateľ odošle údaje zo svojej sieťovej aplikácie po
ich fyzickú prítomnosť v sieti, putujú údaje niekoľkými vrstvami. Celý
proces sa podobá z bežného života dobre známemu procesu odosielania a
prijímanie listových zásielok. Žiak A najprv správu napíše, potom vloží
do obálky, napíše adresu, nalepí známku a odovzdá zásielku na pošte
alebo vhodí do schránky. Poštový úrad zásielku preberie, opečiatkuje
(doplní dátumom prevzatia a miesta podania), triedi a roznáša ich podľa
adresy. Poštový doručovateľ napokon zásielku doručí do poštovej schránky
žiaka B. Ten zásielku vyberie, otvorí obálku a prečíta obsah listu.
Protokol TCP/IP
Protokol TCP/IP bol vyvinutý špeciálne pre účel Internetu a používa sa
od roku 1983. Je to vlastne skupina protokolov,ktorú netvorí len TCP a
IP, ale aj ďalšie, ako napr. UDP, HTTP (Hypertext Transfer Protocol),
FTP (File Transfer Protocol), NNTP (Network News Transport Protocol) a
iné. Pôvodný model prepojovania otvorených systémov bol štvorvrstvový.
Neskoršie bol prepracovaný, doplnený a v roku 1984 prijatý v súčasnosti
používaný sedemvrstvový referenčný model označovaný ako ISO/OSI.
Obsahuje aj štyri vrstvy predchádzajúceho modelu.
7. aplikačná vrstva
|
program
|
6. prezentačná vrstva
|
prevod do tvaru
zrozumiteľného pre príjemcu
|
5. relačná vrstva
|
vytvorenie a údržba
spojenia s príjemcom
|
4. transportná vrstva
|
dozor na spoľahlivý prenos
správ a opravy chýb
|
3. sieťová vrstva
|
vytvorenie paketov s
adresami a ostatnými nutnými časťami
|
2. spojová vrstva
|
vytvorenie rámcov a ich
vysielanie
|
1. fyzická vrstva
|
prenos správ vo forme
elektrických impulzov
|
Koncoví používatelia využívajú počítačové siete prostredníctvom rôznych
sieťových aplikácií - systémov elektronické pošty, prenosu súborov,
vzdialeného prihlasovanie (remote login) a pod. Začleňovať všetky tieto
rôznorodé aplikácie priamo do aplikačnej vrstvy by pre ich veľkú
různorodosť nebolo rozumné. Preto sa do aplikačnej vrstvy včleňujú len
časti týchto aplikácií, ktoré realizujú spoločné resp. všeobecne
použiteľné mechanizmy. Uvažujme ako príklad emuláciu terminálov,
potrebných napríklad pre vzdialené prihlasovanie (remote login). Vo
svete dnes existuje veľké množstvo rôznych terminálov, a realizovať
potrebné prispôsobenie medzi rôznymi typmi terminálov je v podstate
nemožné. Preto se zavádza jeden "referenčný" terminál - tzv. virtuálny
terminál - a pre každý konkrétny typ terminálu se vytvorí len jediné
prispôsobenie medi týmto virtuálnym terminálom a terminálom skutočným.
Prostriedky pre prácu s virtuálnym terminálom pritom sú súčásťou
aplikačnej vrstvy (všade sú rovnaké), zatiaľ čo prostriedky pre
prispôsobenie konkrétnemu terminálu už súčásťou aplikačnej vrstvy nie sú.
Údaje, ktoré sa prostredníctvom siete prenášajú, môžu mať povahu
textov, čísel či všeobecnejších údajových štruktúr. Jednotlivé uzlové
počítače však môžu používať odlišnú vnútornú reprezentáciu týchto údajov
- napríklad strediskové počítače firmy IBM používajú znakový kód
EBCDIC, kým väčšina ostatných pracuje s kódom ASCII. Podobne jeden
počítač môže zobrazovať celé čísla v doplnkovom kóde, druhý počítač v
priamom kódu a pod. Potrebné konverzie prenášaných údajov má na starosti
práve prezentačná vrstva. V rámci tejto vrstvy býva tiež realizovaná
prípadná kompresia prenášaných údajov, eventuélne aj ich šifrovanie.
Úlohou tejto vrstvy je uskotočňovanie (naväzovanie), udržovanie a
rušenie relácií (sessions) medzi koncovými účastníkmi. V rámci
naväzovania relácie si táto vrstva vyžiada na transportnej vrstve
vytvorenie spojenia, prostredníctvom ktorého potom prebieha komunikácia
medzi účastníkmi relácie. Pokiaľ je treba túto komunikáciu nejako riadiť
(napríklad určovať, kdo má kedy vysielať, ak to nemôžu robiť obidvaja
účastníci súčasne), zaisťuje to práve táto vrstva, ktorá má tiež na
starosti všetko, čo je potrebné k ukončeniu relácie a zrušeniu
existujúceho spojenia.
Sieťová vrstva poskytuje bezprostredne vyššej vrstve služby, zaisťujúce
prenos paketov medzi ľubovoľnými dvomi uzlami siete. Transportnú vrstvu
preto úplne odtieňuje od skutečnej topológie siete a vytvára jej tak
ilúziu, že každý uzol siete má přiame spojenie s ktorýmkoľvek iným uzlom
siete. Transportnej vrstve vďaka tomu stačí zaoberať sa už len
komunikácou koncových účastníkov (tzv. end-to-end komunikáciou) - teda
komunikáciou medzi pôvodným odosielateľom a koncovým príjemcom. Pri
odosielaní údajov zaisťuje transportná vrstva zostavovanie jednotlivých
paketov, do ktorých rozdeľuje prenášené údaje, a pri príjme ich zase z
paketov vyberá a skladá do pôvodného tvaru. Dokáže tak zaistiť prenos
ľubovoľne veľkých správ, aj keď jednotlivé pakety majú obmedzenú veľkosť.
Sieťová vrstva zaisťuje prenos celých rámcov, ale iba medzi dvomi
uzlami, medzi ktorými vedie priame spojenie. Čo ale robiť, ak spojenie
medzi príjemcom a odosielateľom nie je priame, ale vedie cez jeden či
viac medziľahlých uzlov. Potom musí nastúpiť sieťová vrstva, ktorá
zaistí potrebné smerovanie (routing) prenášaných rámcov, označovaných
teraz už ako pakety (packets). Sieťová vrstva teda zaisťuje voľbu
vhodnej trasy resp. cesty (route) cez medziľahlé uzly, a tiež postupný
prenos jednotlivých paketov po tejto trase od pôvodného odosieľateľa až
ku koncovému príjemcovi. Sieťová vrstva si teda musí "uvedomovať"
konkrétnu topológiu siete (spôsob vzájomného priameho prepojenia
jednotlivých uzlov).
Fyzická vrstva poskytuje ako svoje služby prostriedky pre prenos
jednotlivých bitov. Bezprostredne vyššia spojová vrstva (niekedy
nazývaná aj linková vrstva alebo vrstva dátového spoja) má za úlohu
zaistiť pomocou týchto služieb bezchybný prenos celých blokov údajov
(rádove stovky bytov), označovaných jako rámce (frames). Keďže fyzická
vrstva nijako neinterpretuje jednotlivé prenášané bity, je iba na
spojovej vrstve, aby správne rozpoznala začiatok a koniec rámca, i jeho
jednotlivých častí.
Úloha tejto vrstvy je zdanlivo veľmi jednoduchá - zaistiť prenos
jednotlivých bitov medzi príjemcom a odosielateľom prostredníctvom
fyzickej prenosovej cesty, kterú táto vrstva bezprostredne ovláda. Na to
je ale treba vyriešiť mnoho otázok prevažne technického charakteru -
napr. akou úrovňou napätia bude reprezentovaná logická jednotka a akou
logická nula, ako dlho "trvá" jeden bit, koľko kontaktov a aký tvar majú
mať konektory káblov, aké signály sú týmito káblami prenášané, aký je
ich význam, časový priebeh a podobne.
UDP
Protokol UDP (User Datagram Protocol) je vlastne alternatíva TCP. Jedná
se o tak zvanú nespojovanú službu. Nespojovaná služba znamená, že
nedochádza k naviazaniu spojenia. Jednoducho odošleme údaje na danú IP
adresu a daný UDP port a nevieme, či údaje dorazili a či se nepoškodili.
Žiadne potvrdenie ani nič podobného nepríde. UDP protokol je vhodný
najmä v situáciách, kde by spojenie pomocou TCP bolo veľkou záťažou pre
sieť (napríklad ak sa obraciame na nadradený DNS server). U TCP paketov
sa musí posielať potvrdenie. U UDP paketov nie. Súčasťou UDP hlavičky
je tiež port. Ide v rámci počítača tiež o jednoznačné označenie
aplikácie. Číslovanie TCP a UDP portov je na sebe nezávislé. Napríklad
jedna aplikácia môže mať ppriradený TCP port 1024 ale UDP port 1024 môže
byť priradený druhej aplikácií.
Socket
Socket je mechanizmus pre komunikáciu. Prvý krát sa objavil v OS BSD.
Socket je veľmi všeobecný nástroj, možno sním pracovať ako so súborom,
má pridelený vlastný jedinečný deskriptor. Rovnaké funkcie môžeme
používať pre komunikáciu pomocou rôznych protokolov.
Resolve
Domain Name
/* resolve_domain_name */
#include <stdio.h> #include <netdb.h> #include <netinet/in.h> #include <arpa/inet.h>
int main(int argc, char **argv) { struct hostent *host; char **aliases; register int i;
/* osetrenie poctu argumentov */ if (argc != 2) { printf("Pouzitie: %s domain_name\n", argv[0]); printf("Napríklad: %s localhost\n", argv[0]); return(-1); }
/* osetrenie existencie adresy (domain_name) */ if (!(host=gethostbyname(argv[1]))) { printf("Chyba: nepodarilo sa najst %s\n", argv[1]); return(-1); }
/* udaje o stroji s adresou domain_name */ printf("Meno: %s\n", host->h_name); printf("Aliasy:"); aliases=host->h_aliases; while (*aliases) { printf(" %s", *(aliases++)); } i=0; printf("\nIP adresy:"); while (host->h_addr_list[i]) { /* inet_ntoa() prevod do "bodkoveho" tvaru */ printf(" %s", inet_ntoa(*(struct in_addr *)host->h_addr_list[i++])); } printf("\nPocet IP adries: %i\n", i); printf("Velkost IP adries: %iB\n", host->h_length);
return 0; }
Klávesnica
v konzole
Žiaci, ktorí programovali v jazyku Pascal, dobre poznajú funkciu KeyPressed. Žiaci, ktorí programovali v jazyku
C v OS M$ DOS zase dobre poznajú funkciu kbhit(). Linuxový (unixový)
ekvivalent funkcie, ktorá by zistila, či bola alebo nebola stlačená
nejaká klávesa (bez toho, že by ju čítala) neexistuje. V súbore kbhit.c
sú funkcie emulujúce DOSovskú funkciu kbhit(). Funkcia init_kbhit()
mení nastavenie terminálu na čítanie jedného znaku, funkcia kbhit()
upraví jeho chovanie, čaká na vstup a ihneď vráti riadenie programu a
funkcia close_kbhit()
obnoví pôvodné nastavenie terminálu.
/* void init_kbhit(void) inicializuje kbhit */ /* int kbhit(void) vracia ascii kod stlacenej klavesy alebo nulu ak nebolo nic stlacene */ /* void close_kbhit(void) konci pracu s kbhit */
#include <termios.h> #include <term.h> #include <curses.h>
/* deklaracia struktur pre nastavenie terminalu */ struct termios initial_settings; struct termios new_settings; /* premenna pre detekciu stlacenej klavesy */ int peek_character=-1;
/*******************************/ int kbhit(void) { int key=0; if (kbhit_on()) key=readkey_on(); return(key); }
/*******************************/ void init_kbhit(void) { tcgetattr(0, &initial_settings); new_settings=initial_settings; new_settings.c_lflag &= ~ICANON; new_settings.c_lflag &= ~ECHO; new_settings.c_lflag &= ~ISIG; new_settings.c_cc[VMIN]=1; new_settings.c_cc[VTIME]=0; tcsetattr(0, TCSANOW, &new_settings); }
/*******************************/ void close_kbhit(void) { tcsetattr(0, TCSANOW, &initial_settings); }
int kbhit_on(void) { char ch; int nread;
if (peek_character != -1) return(1); new_settings.c_cc[VMIN]=0; tcsetattr(0, TCSANOW, &new_settings); nread=read(0, &ch, 1); new_settings.c_cc[VMIN]=1; tcsetattr(0, TCSANOW, &new_settings); if (nread==1) { peek_character=ch; return(1); }
return(0); }
int readkey_on(void) { char ch;
if (peek_character!=-1) { ch=peek_character; peek_character=-1; return(ch); }
read(0, &ch, 1); return(ch); }
TCP/IP
Client
/* test_tcp_client */
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <netdb.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <string.h> #include <errno.h> #include "kbhit.c"
#define SIZEMSG 1024
extern int errno; extern int h_errno;
int main(int argc, char *argv[]) { char recv_msg[SIZEMSG]; // prijata sprava char send_msg[SIZEMSG]; // odoslana sprava struct hostent *server_host; // struct servera struct sockaddr_in server_sock; // struct serveroveho socketu int my_sock_fd ; // file deskriptor mojho client socketu int server_port; // cislo portu int count_byte; // pocet prijatych a odoslanych byte int i; int key=0; // stlacena klavesa (kbhit)
system("clear"); printf("TCP/IP socketova komunikacia [CLIENT]\n"); system("date"); printf("\n");
/* osetrenie poctu argumentov */ if (argc != 3) { printf("Pouzitie: %s adresa_servera port_servera\n", argv[0]); printf("Napriklad: %s localhost 1024\n\n", argv[0]); return(-1); }
/* osetrenie existencie adresy servera (domain_name) a vypis infa o nom */ if (!(server_host=gethostbyname(argv[1]))) { printf("Chyba: Nepodarilo sa najst server %s [%i]\n", argv[1], h_errno); herror("Chyba"); // textovy vypis chyby h_errno switch (h_errno) { case HOST_NOT_FOUND: printf(" Specifikovaný server je neznamy [HOST_NOT_FOUND]\n"); break; case NO_ADDRESS: printf(" Meno servera je platne, ale nema ziadnu IP adresu [NO_ADDRESS]\n"); break; case NO_RECOVERY: printf(" Neodstranitelna chyba menneho servera [NO_RECOVERY]\n"); break; case TRY_AGAIN: printf(" Docasna chyba menneho servera [TRY_AGAIN]\n"); break; default: printf(" Radsej sa chod prejst po lese\n"); break; } printf("\n"); return(-1); } printf("... server %s najdeny [OK]\n", argv[1]); printf(" meno servera: %s\n", server_host->h_name); i=0; printf(" IP adresa servera:"); while (server_host->h_addr_list[i]) { /* inet_ntoa() prevod do "bodkoveho" tvaru */ printf(" %s", inet_ntoa(*(struct in_addr *)server_host->h_addr_list[i++])); } printf("\n\n");
/* vytvorenie mojho lokalneho client socketu (socket) */ if ((my_sock_fd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==-1) { printf("Chyba: nepodarilo sa vytvorit socket\n\n"); return(-1); } printf("... socket [%i] vytvoreny [OK]\n\n", my_sock_fd);
/* naplnenie struktury server_sock (sockaddr_in) */ server_port = atoi(argv[2]); server_sock.sin_family = AF_INET; // rodina protokolu server_sock.sin_port = htons(server_port); // cislo portu na serveri // IP adresa servera ako kopia polozky struktury server_host memcpy(&(server_sock.sin_addr), server_host->h_addr, server_host->h_length);
/* pripojenie (connect) */ if (connect(my_sock_fd, (struct sockaddr *)&server_sock, sizeof(server_sock))==-1) { printf("Chyba: nepodarilo sa naviazat spojenie so serverom %s [%i]\n", argv[1], errno); herror("Chyba"); // textovy vypis chyby errno switch (errno) { case EBADF: printf(" Zly deskriptor socketu [EBADF]\n"); break; case EFAULT: printf(" Adresa socketu je mimo adresovy priestor procesu [EFAULT]\n"); break; case ENOTSOCK: printf(" Deskriptor nie je platnym deskriptorom socketu [ENOTSOCK]\n"); break; case EISCONN: printf(" Socket je uz spojeny [EISCONN]\n"); break; case ECONNREFUSED: printf(" Spojeníe bolo odmietnute serverom [ECONNREFUSED]\n"); break; case ETIMEDOUT: printf(" Casovy limit pre spojenie vyprsal [ETIMEDOUT]\n"); break; case ENETUNREACH: printf(" Síet nie je dosiahnutelna [ENETUNREACH]\n"); break; case EADDRINUSE: printf(" Adresa je uz pouzivana [EADDRINUSE]\n"); break; default: printf(" Radsej sa chod prejst po lese\n"); break; } printf("\n"); return(-1); } printf("... spojenie so serverom naviazane [OK]\n\n");
/* ---------------------------------------------------------------- */
printf("[q]-quit (ukoncenie klienta)\n[s]-send (posli spravu serveru)\n\n"); init_kbhit();
/* cyklus odosielania a prijimania sprav */ while (key!='q') { key=kbhit(); if (key=='s') { strcpy(send_msg, ""); /* nacitanie spravy z klavesnice */ printf("<send> "); close_kbhit(); fgets(send_msg, SIZEMSG, stdin); // printf("\n"); init_kbhit(); /* odoslanie spravy (send) */ count_byte=0; if ((count_byte=send(my_sock_fd, send_msg, SIZEMSG, 0))==-1) { printf("Chyba: nepodarilo sa odoslat spravu\n\n"); } } /* prijem spravy (recv) */ strcpy(recv_msg, ""); count_byte=0; if ((count_byte=recv(my_sock_fd, recv_msg, SIZEMSG, MSG_DONTWAIT))>0) { printf("\a<recv> %s", recv_msg); // printf("\n\n"); }
} // koniec whileho /* uzatvorenie spojenia (close) */ close_kbhit(); close(my_sock_fd); printf("\n... socket uzatvoreny [OK]\n"); printf("... spojenie ukoncene [OK]\n"); printf("... cinnost klienta ukoncena [OK]\n\n"); return(0); }
TCP/IP
Server
/* test_tcp_server */
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <netdb.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <string.h> #include "kbhit.c"
#define SIZEMSG 1024 #define SIZEFRONT 1
extern int h_errno;
int main(int argc, char *argv[]) { char recv_msg[SIZEMSG]; // prijata sprava char send_msg[SIZEMSG]; // odoslana sprava struct sockaddr_in server_sock; // struct serveroveho socketu struct sockaddr_in client_sock; // struct klientskeho socketu socklen_t client_len; // dlzka adresy klienta int server_port; // cislo portu int my_sock_fd; // file deskriptor mojho server socketu int client_sock_fd; // file deskriptor klientskeho socketu int count_byte; // pocet prijatych a odoslanych byte int key=0; // stlacena klavesa (kbhit) unlink("server_socket"); system("clear"); printf("TCP/IP socketova komunikacia [SERVER]\n"); system("date"); printf("\n");
/* osetrenie poctu argumentov */ if (argc != 2) { printf("Pouzitie: %s port_servera\n", argv[0]); printf("Napriklad: %s 1024\n\n", argv[0]); return(-1); }
/* vytvorenie mojho lokalneho server socketu (socket) */ if ((my_sock_fd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==-1) { printf("Chyba: nepodarilo sa vytvorit socket\n\n"); return(-1); } printf("... socket [%i] vytvoreny [OK]\n\n", my_sock_fd);
/* naplnenie struktury server_sock (sockaddr_in) */ server_port = atoi(argv[1]); server_sock.sin_family = AF_INET; // rodina protokolu server_sock.sin_port = htons(server_port); // cislo portu na serveri server_sock.sin_addr.s_addr = INADDR_ANY; // moze sa pripojit kazdy (INADDR_ANY)
/* pomenovanie socketu (bind) */ if (bind(my_sock_fd, (struct sockaddr *)&server_sock, sizeof(server_sock))==-1) { printf("Chyba: nepodarilo sa pomenovat socket\n\n"); return(-1); } printf("... socket [%i] pomenovany [OK]\n\n", my_sock_fd); /* vytvorenie fronty ziadosti o pripojenie (listen) */ if (listen(my_sock_fd, SIZEFRONT)==-1) { printf("Chyba: nepodarilo sa vytvorit frontu ziadosti o pripojenie\n\n"); return(-1); } printf("... fronta ziadosti o pripojenie vytvorena [OK]\n\n"); /* prijatie klienta (accept) */ client_len=sizeof(client_sock); if ((client_sock_fd=accept(my_sock_fd, (struct sockaddr *)&client_sock, &client_len))==-1) { printf("Chyba: nepodarilo sa akceptovat ziadost o pripojenie"); return(-1); } printf("... ziadost o pripojenie akceptovana [OK]\n"); printf(" IP adresa klienta: %s\n", inet_ntoa((struct in_addr)client_sock.sin_addr)); printf(" spojenie so serverom naviazane [OK]\n\n");
/* ---------------------------------------------------------------- */
printf("[q]-quit (ukoncenie servera)\n[s]-send (posli spravu klientovi)\n\n"); init_kbhit();
/* cyklus odosielania a prijimania sprav */ while (key!='q') { key=kbhit(); if (key=='s') { strcpy(send_msg, ""); /* nacitanie spravy z klavesnice */ printf("<send> "); close_kbhit(); fgets(send_msg, SIZEMSG, stdin); // printf("\n"); init_kbhit(); /* odoslanie spravy (send) */ count_byte=0; if ((count_byte=send(client_sock_fd, send_msg, SIZEMSG, 0))==-1) { printf("Chyba: nepodarilo sa odoslat spravu\n\n"); } } /* prijem spravy (recv) */ strcpy(recv_msg, ""); count_byte=0; if ((count_byte=recv(client_sock_fd, recv_msg, SIZEMSG, MSG_DONTWAIT))>0) { printf("\a<recv> %s", recv_msg); // printf("\n\n); }
} // koniec whileho /* uzatvorenie spojenia (close) */ close_kbhit(); close(my_sock_fd); close(client_sock_fd); printf("\n... socket uzatvoreny [OK]\n"); printf("... spojenie ukoncene [OK]\n"); printf("... cinnost servera ukoncena [OK]\n\n"); return(0); }
Manuálové
stránky
resolve_domain_name
header:
<netdb.h>
<netinet/in.h>
<arpa/inet.h>
struct:
hostent
in_addr
function:
tcp_client
header:
<unistd.h>
<netdb.h>
<netinet/in.h>
<sys/types.h>
<sys/socket.h>
<arpa/inet.h>
<errno.h>
struct:
hostent
sockaddr_in
sockaddr
function:
tcp_server
header:
<unistd.h>
<sys/types.h>
<sys/socket.h>
<netinet/in.h>
<arpa/inet.h>
<unistd.h>
struct:
sockaddr_in
sockaddr
function:
Download
sockety.tgz
Záver
Toľko úvod do oblasti socketov. Námetom pre ďalšiu činnosť žiakov môže
byť obslúženie viacerých klientov (funkcie fork(), select() a pod.)
prípadne programovanie viacerých samostatných vlákien a následné
porovnanie s predchádzajúcou realizáciou. Tiež je možné pracovať so
socketmi na "low-level" úrovni prostredníctvom file deskriptorov
(funkcie write(), read() a pod.). Nemenej dôležitou oblasťou je otázka
bezpečnosti komunikácie, šifrovania.
Zdroje
- manuálové stránky (RedHat 7.3)
- Neil Mathew, Richard Stones - Linux Začínáme programovat
- seriál článkov o socketoch na http://www.builder.cz
- Príručka správcu siete pre školy podporované projektom
Infovek (LŠOG Zvolen 2002)
Najmä kniha N.Mathew, R.Stones - Linux Začínáme programovat by nemala
chýbať na žiadnej základnej škole.
|