C Socket Programming in the UNIX environment - part 5 12 Dicembre 2007
Posted by Calogero in C, GNU/Linux, Informatica, Networking, Programmazione, Sistemi Operativi, Unix.Tags: bind, client, daytime, server, setsockopt, socket, TCP/IP, thread
trackback
Ecco il codice di una semplicissima applicazione client-server che simula il servizio daytime. In maniera molto banale, il client si connette al server per ottenere data e ora corrente.
Ecco il codice del server:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <time.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BACKLOG 10
int main (int argc, const char * argv[]) {
int list_fd,conn_fd;
struct sockaddr_in serv_add;
char buffer[80];
time_t timeval;
//creiamo la socket
if((list_fd=socket(AF_INET,SOCK_STREAM,0))<0){
perror("socket creation error\n");
exit(-1);
}
//la funzione memset azzera la memoria riservata alla struttura serv_add
memset((void*)&serv_add,0,sizeof(serv_add));
//inizializziamo la struttura in maniera opportuna
serv_add.sin_family=AF_INET; //specifica che useremo il protocollo IPv4
serv_add.sin_port=htons(13); //specifichiamo la porta su cui si mette in ascolto il server
//usiamo la htons per impostare il valore corretto in network byte order
serv_add.sin_addr.s_addr=htonl(INADDR_ANY);
//la funzione setsockopt permette di impostare delle opzioni per la socket che
//si sta usando.
//in particolare, questa chiamata alla funzione permette di riutilizzare la porta
//della socket anche dopo che la connessione è stata chiusa.
//senza la chiamata a questa funzione, alla chiusura della connessione la porta appena
//usata non è momentaneamente disponibile, perchè risulta esser ancora allocata a livello kernel
int yes=1;
if(setsockopt(list_fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))<0){
perror("setsockopt\n");
exit(-1);
}
//facciamo il binding della socket con la struttura che descrive l'indirizzo
if(bind(list_fd,(struct sockaddr*)&serv_add,sizeof(serv_add))<0){
perror("bind error\n");
exit(-1);
}
//mettiamo il server in ascolto sulla socket
if(listen(list_fd,BACKLOG)<0){
perror("listen error\n");
exit(-1);
}
//all'interno del ciclo while il server accetta le connessioni
//la funzione 'accept' restituisce la socket su cui il server gestirà la connessione
//col client
while(1){
struct sockaddr_in tmp;
unsigned int addrlen=sizeof(tmp);
memset((void*)&tmp,0,sizeof(tmp));
if((conn_fd=accept(list_fd,(struct sockaddr*)NULL,NULL))<0){
perror("accept error\n");
exit(-1);
}
//la funzione getpeername permette di ottenere informazioni sul client
//la funzione prende come argomenti la socket di connessione,
//una struttura di tipo sockaddr_in e un puntatore alla dimensione
//in bytes della struttura
getpeername(conn_fd,(struct sockaddr*)&tmp,&addrlen);
//attraverso la funzione inet_ntoa trasformiamo l'indirizzo del client in una stringa in notazione decimale puntata
printf("Client IP: %s\nClient port: %d\n",inet_ntoa(tmp.sin_addr),tmp.sin_port);
timeval=time(NULL);
//il server calcola la data corrente e la manda al client attraverso la funzione write
snprintf(buffer,sizeof(buffer),"%.24s\r\n",ctime(&timeval));
//la funzione write prende come argomenti:
//1) la socket di connessione
//2) il buffer contenente le informazioni da trasmettere
//3) la lunghezza del buffer in bytes
//il secondo parametro della write è un void*
if(write(conn_fd,buffer,strlen(buffer))<0){
perror("write error\n");
exit(-1);
}
//chiudiamo la connessione
close(conn_fd);
}
return 0;
}
Ecco il codice del client:
#include <stdio.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main (int argc, const char * argv[]) {
int sock_fd; //descrittore della socket
int nread;
struct sockaddr_in serv_add; //conterrà le informazioni relative al server
char buffer[80];
char indirizzo_server[]="127.0.0.1";
//crea la socket TCP
if( (sock_fd=socket(AF_INET,SOCK_STREAM,0))<0 ){
perror("Socket creation error\n");
return -1;
}
//inizializza l'indirizzo del server
//azzeriamo la struttura che descrive la socket
memset((void*)&serv_add,0,sizeof(struct sockaddr_in));
serv_add.sin_family=AF_INET; //address family inet IPv4
serv_add.sin_port=htons(13); //definiamo il numero di porta
//in particolare la funzione htons converte
//bytes in host order in bytes in network order
//la funzione inet_pton converte una stringa "dotted decimal" in un indirizzo "utile"
if( inet_pton(AF_INET,indirizzo_server,&serv_add.sin_addr) <= 0){
perror("Address creation error\n");
return -1;
}
//stabilisce la connessione
if(connect(sock_fd,(struct sockaddr*) &serv_add,sizeof(serv_add))<0){
perror("Connection error");
return -1;
}
//legge le informazioni trasmesse dal server
while((nread=read(sock_fd,buffer,80))>0){
buffer[nread]=0;
if(fputs(buffer,stdout)==EOF){
perror("fputs error");
return -1;
}
}
if(nread<0){
perror("Read error");
return -1;
}
close(sock_fd);
return 0;
}
Possiamo notare come il server di cui ho postato il codice non è un server “concorrente”, ma “iterativo”. Ciò vuol dire che questo server è in grado di servire una sola richiesta alla volta. Per implementare un server concorrente è necessario saper gestire la crezione e l’esecuzione di processi e thread in concorrenza. Spero in futuro di poter parlare di questi argomenti (tempo permettendo!).
Buona programmazione. (I file sorgente li trovate qui)
















Ciao, affinchè il server funzioni devi sostituire socket_fd con list_fd, altrimenti nemmeno compila.
Vedi sotto:
—–
int yes=1; if(setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))<0){
^^^^^
list_fd
perror(”setsockopt\n”);
exit(-1);
}
——
Samuele
Grazie per la segnalazione!
Ciao,
io qnd vado a compilare in windows ricevo un errore sull’include di arpa/inet.h…nn lo trova
mentre se compilo in linux (ubuntu aggiornato) mi da errori a cascata e immagino che la causa sia che non ho le librerie incluse….
dove posso trovarle?
grazie per l’aiuto!
E` normale che su windows non trovi arpa/inet.h. Secondo te perchè il post s’intitola “C socket programming in the Unix environment”? Da che mondo è mondo, windows non è un sistema Unix. Il fatto che su ubuntu ti dia errore è strano. Le librerie che servono devon esserci per forza.Che errori da?
Si pensavo che le librerie avrebbe dovuto trovarle in ogni caso….cmq su linux ho risolto grazie.