1 programmazione con socket. 2 cosè un socket? uninterfaccia per la comunicazione tra processi che...
TRANSCRIPT
1
Programmazione con socket
2
Cos’è un socket?
• Un’interfaccia per la comunicazione tra processi che utilizza i file descriptor di UNIX
• “everything in UNIX is a file”• Tipi di socket:
– Internet Socket– Unix Socket– etc…..
3
Internet Socket
• Ci sono due tipi principali di Socket:– Stream Socket (SOCK_STREAM)
• Reliable
• Two way connected
• Utilizzano il Transmission Control Protocol (RFC.793)
– Datagram Socket (SOCK_DGRAM)• Not reliable
• Connectionless
• Utilizzano lo User Datagram Protocol (RFC. 768)
4
Comunicazione Browser/Server Web
Browser Server Web
GET / HTTP\1.1
HTTP\1.1 200 OK
<HTML>…..</HTML>
5
Come avviene la comunicazione?
Browser
TCP
IP
UDP
TSAP
Server Web
TCP
IP
UDP
TSAPAPI fornite dal S.O.
Il Transport Service Access Point è individuato da un indirizzo di livello 3 (indirizzo IP) ed un indirizzo di livello 4 (port TCP) composto da 16 bit.
6
socket()
bind()
listen()
accept()
read()
write()
read()
close()
socket()
connect()
write()
read()
close()
Connessione instaurata
Richiesta
Risposta
Stream Socket communication
7
Strutture C• Socket descriptor: int • Indirizzo di un socket generico:
struct sockaddr { unsigned short sa_family; // address family, AF_xxx char sa_data[14]; // 14 bytes of protocol
address };
• Indirizzo di un Internet Socketstruct sockaddr_in {
short int sin_family; // Address family unsigned short int sin_port; // Port number struct in_addr sin_addr; // Internet address unsigned char sin_zero[8]; // Same size as struct sockaddr
}; struct in_addr {
unsigned long s_addr; // that's a 32-bit long, or 4 bytes };
8
Conversione Big-Endian / Little-Endian
• Network Byte Order = Big Endian
• Host Byte Order = Big or Little Endian
• Funzioni per la conversionehtons() – “Host to Network Short”
htonl() – “Host to Network Long”
ntohs() – “Network to Host Short”
ntohl() – “Network to Host Long”
9
Funzioni utili
• in_addr_t inet_addr (const char *str);
restituisce il valore a 32-bit, nell’ordine di rete, ottenuto dalla conversione della stringa puntata da str.
In caso di errore restituisce INADDR_NONE
10
funzione socket()La prima azione per fare dell’I/O da rete è la chiamata alla funzione
socket() specificando il tipo di protocollo di comunicazione da utilizzare
(TCP, UDP, Unix domain stream protocol per usare le pipe).
#include <sys/socket.h>
int socket (int family, int type, int protocol);
restituisce un descrittore di socket maggiore o uguale a zero, oppure -1
in caso di errore.
11
funzione socket()• int socket (int family, int type, int protocol);
• family specifica la famiglia di protocolli da utilizzare.PF_INET IPv4 protocolPF_INET6 IPv6 protocolPF_LOCAL Unix domain protocols (ex PF_UNIX)
• type specifica quale tipo di protocollo vogliamo utilizzare all’interno della famiglia di protocolli specificata da family.
SOCK_STREAM socket di tipo stream (connesso affidabile)SOCK_DGRAM socket di tipo datagramSOCK_RAW socket di tipo raw (livello network)
• protocol di solito è settato a 0, tranne che nel caso dei socket raw.
12
funzione connect()
• La funzione connect() è usata per stabilire una connessione con un server TCP.
#include <sys/socket.h>
int connect (int socketfd, const struct sockaddr *servaddr, int addrlen);
restituisce 0 se la connessione viene stabilita, -1 in caso di errore.
13
funzione connect()
int connect (int socketfd, const struct sockaddr *servaddr, int addrlen);
• socketfd è un descrittore socket ottenuto da una chiamata alla funzione socket().
• servaddr è un puntatore alla struttura sockaddr_in, e deve specificare l’indirizzo IP e il numero di porta del server al quale connettersi.
• addrlen specifica la dimensione della struttura dati che contiene l’indirizzo del server servaddr, viene di solito assegnata mediante la sizeof(servaddr).
Il client può non specificare il proprio indirizzo IP e la propria porta, chiedendo al sistema operativo di assegnargli una porta TCP qualsiasi e come indirizzo IP l’indirizzo della sua interfaccia di rete. Quindi non è necessaria la chiamata alla bind() prima della connect().
14
funzione bind()
• La funzione bind() collega al socket un indirizzo locale. Per TCP e UDP ciò significa assegnare un indirizzo IP ed una porta a 16-bit.
#include <sys/socket.h>
int bind (int sockfd, const struct sockaddr *myaddr, int addrlen);
restituisce 0 se tutto OK, -1 in caso di errore.
15
funzione bind()
int bind (int sockfd, const struct sockaddr *myaddr, int addrlen);
• sockfd è un descrittore ottenuto da una chiamata socket().
• myaddr è un puntatore alla struttura sockaddr_in, e specifica l’eventuale indirizzo IP locale e l’eventuale numero di porta locale a cui il sistema operativo deve collegare il socket.
• addrlen specifica la dimensione della struttura myaddr.
16
funzione bind()
• Chiamando la bind() si può specificare o no l’indirizzp IP e la porta, assegnando valori ai due campi sin_addr e sin_port della struttura sockaddr_in
• L’assegnazione viene fatta con le istruzioni:
struct sockaddr_in localaddr;
localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
localaddr.sin_port = htons(port_number);
17
funzione listen()
• La funzione listen è utilizzata solo per implementare un server TCP e esegue due azioni:1) ordina al kernel di far passare il socket dallo stato iniziale CLOSED allo stato LISTEN, e di accettare richieste di inizio connessione per quel socket, mettendole in una coda del kernel.
• 2) specifica al kernel quante richieste di inizio connessione può accodare al massimo per quel socket.
#include <sys/socket.h>int listen (int socketfd, int backlog );
restituisce 0 se tutto OK, -1 in caso di errore.
18
funzione listen()
int listen (int socketfd, int backlog );
• socketfd è un descrittore ottenuto da una chiamata socket().
• backlog è un intero che specifica quante richieste di inizio connessione il kernel può mantenere in attesa nelle sue code.
19
funzione accept()
• La funzione accept è chiamata solo dal TCP server e restituisce la prima entry nella coda delle connessioni già completate per quel socket. Se la coda è vuota la accept resta in attesa
.
#include <sys/socket.h>
int accept (int socketfd, struct sockaddr *cli_addr, int *ptraddrlen);
restituisce un descrittore socket >=0 se tutto OK, -1 in caso di errore.
20
funzione accept()
int accept (int socketfd, struct sockaddr *cli_addr, int *ptraddrlen);
• socketfd è un descrittore ottenuto da una chiamata a socket() sul quale sono state effettuate le chiamate bind() e listen(). Tale listening socket viene utilizzato per accedere alla coda delle connessioni instaurate come si è visto nella funzione listen().
• cli_addr è un puntatore alla struttura sockaddr_in, su cui la funzione accept scrive l’indirizzo IP e il numero di porta del client, con cui è stata instaurata la connessione a cui si riferisce il socket che viene restituito come risultato .
• ptraddrlen è un puntatore alla dimensione della struttura cli_addr che viene restituita.
21
funzione close()
• La funzione close è utilizzata è utilizzata per chiudere un socket e terminare una connessione TCP.
int close (int socketfd);
restituisce 0 se tutto OK, -1 in caso di errore.
• socketfd è un descrittore di socket.
22
funzione send()
int send (int socketfd, const void* msg, int len, unsigned int flags);
• La funzione send cerca di scrivere un numero byte pari a len sul file descriptor socketfd, leggendoli dal buffer puntato da msg.Se len è maggiore di zero viene effettuata la scrittura e viene restituito il numero di byte scritti.
23
funzione recv()
int recv (int socketfd, const void* buf, int len, unsigned int flags);
• La funzione recv cerca di leggere un numero di byte pari a len dal file descriptor socketfd, scrivendoli nel buffer puntato da buf. Se len è maggiore di zero viene effettuata la lettura e viene restituito il numero di byte letti. Se viene restituito zero significa end-of-file (fine stream).
-1 indica che si è verificato un errore.
24
funzione gethostbyname()
• struct hostent* gethostbyname( char *name );Prende una stringa che contiene il nome dell’host e restituisce una struttura hostent che contiene l’indirizzo (gli indirizzi) IP dell’host.
Struct hostent {char *h_name; //official host namechar **h_aliases; //other aliasesint h_length; //address typechar **h_addr_list; //list of addresses
}
25
socket()
bind()
recvfrom()
sendto()
close()
socket()
sendto()
recvfrom()
close()
Richiesta
Risposta
Datagram Socket communication
26
funzione sendto()
int sendto (int socketfd, const void* msg, int len, unsigned int flags, struct sockaddr *to, int *tolen);
• to è un puntatore a una struct sockaddr che contiene l’indirizzo IP e la porta della destinazione.
• tolen può essere inizializzato a sizeof(struct sockaddr)
27
funzione recvfrom()
• int recvfrom (int socketfd, const void* buf, int len, unsigned int flags, struct sockaddr *from, int * fromlen);
• from è un puntatore a una struct sockaddr che sarà riempita con l’indirizzo IP e la porta della macchina che si è connessa
• fromlen va inizializzato a sizeof(struct sockaddr)
28
Esempio Client TCP
…
s = socket(PF_INET, SOCK_STREAM, 0);
indirizzo.sin_family = AF_INET;
indirizzo.sin_port = htons(80);
if ((indirizzo.sin_addr.s_addr = inet_addr("130.251.12.32")) = = INADDR_NONE ) {
perror("inet_addr fallita");
return 1;
}
29
Esempio Client TCP (2)
if (connect(s,(struct sockaddr *) &indirizzo,sizeof(struct sockaddr_in))!=0) {
perror("connect fallita");
return 1;
}
nw = send(s,messaggio,strlen(messaggio),0);
n=recv(s,buffer,20000,0);
close(s);
30
Esempio Server TCP…
s = socket(PF_INET,SOCK_STREAM,0);
indirizzo.sin_family = AF_INET;
indirizzo.sin_port = htons(8120);
if (bind(s,&indirizzo,sizeof(struct sockaddr_in))!=0){
perror("bind fallita");
return 1;
}
if (listen(s,3)!=0){
perror("Listen fallita");
return 1;
}
31
Esempio Server TCP (2)
t=accept(s,NULL,0);
if (t== -1){
perror("Accept fallita");
return 1;
}
lungh=recv(t,buffer,1000,0);
if (lungh < 1 ){
perror("Read fallita");
return 1;
}
…
32
Esempio Client UDP
…
remoteServAddr.sin_family = AF_INET; remoteServAddr.sin_addr.s_addr = inet_addr(“130.251.12.14");
remoteServAddr.sin_port = htons(8000);
sd = socket(AF_INET,SOCK_DGRAM,0);
if(sd<0) { printf("cannot open socket \n"); exit(1); }
msg = “MESSAGGIO";
rc = sendto(sd, msg , strlen(msg)+1, 0, (struct sockaddr *) &remoteServAddr, sizeof(remoteServAddr));
33
Esempio Server UDP
….
sd=socket(AF_INET, SOCK_DGRAM, 0);
if(sd<0) { printf("cannot open socket \n"); exit(1); }
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(LOCAL_SERVER_PORT);
rc = bind (sd, (struct sockaddr *) &servAddr,sizeof(servAddr));
if(rc<0) { printf("cannot bind port number %d \n", LOCAL_SERVER_PORT); exit(1); }
34
Esempio Server UDP (2)
while(1) {
memset(msg,0x0,MAX_MSG);
cliLen = sizeof(cliAddr);
n = recvfrom(sd, msg, MAX_MSG, 0, (struct sockaddr *) &cliAddr, &cliLen);
if(n<0) { printf("cannot receive data \n"); continue; }
}