C++ e la programmazione dei socket

La programmazione dei socket in C++ è il modo di combinare o connettere due nodi tra loro in una rete in modo che possano comunicare facilmente senza perdere dati. Ad esempio, la presa elettrica che vediamo nella realtà di ogni giorno è un mezzo per collegare due dispositivi o sistemi. Allo stesso modo, i socket consentono alle applicazioni di collegarsi alla rete locale su porte diverse.

Ogni volta che viene creato un socket, il programma deve specificare il tipo di socket e l’indirizzo del dominio.

Prerequisiti per le prove di codice

Prima di iniziare, diamo spesso per scontato che chi si imbatte in queste pagine sia gia al corrente degli strumenti minimi per poter effettuare delle prove di codice. A tale proposito ricordiamo che per provare queste semplici righe di codice sono necessari i seguenti strumenti software:

  • IDE per la stesura e compilazione del codice
  • Applicazione TERMINALE per la prova del codice compilato

Il codice per il controllo di un socket

Nella pagina principale della nostra procedura in C++ bisogna includere questo file di intestazione per utilizzare la funzione socket nel codice:

#include <sys/socket.h>
int socket ( int domain, int type, int protocol );

Metodi di programmazione di un socket in linguaggio C++

Una classe Socket può essere utilizzata per creare un socket nella programmazione in C++. I metodi possono essere creati in molti modi. Ad esempio uno di essi è:

#public Socket( InetAddress address, int port )
throws IOException

Elenco dei metodi Socket utilizzabili nella programmazione

  • public InputStream getInputStream() – Dopo aver creato un socket abbiamo bisogno di un metodo per ottenere input dall’utente in qualche modo. Questo metodo del flusso di input restituirà l’InputStream che rappresenta i dati collegati a questo socket. Genera anche un’eccezione. Assicurarsi che l’oggetto venga restituito ogni volta che si chiama questo metodo per evitare errori.
  • public OutputStream getOutputStream() – Dopo aver creato un socket abbiamo bisogno di un metodo per ottenere l’output dall’utente in qualche modo. Questo metodo del flusso di output restituirà OutputStream che rappresenta i dati collegati a questo socket. Genera anche un’eccezione. Assicurarsi che l’oggetto venga restituito ogni volta che si chiama questo metodo per evitare errori.
  • public synchronized void close() – Una volta creato un socket dobbiamo chiuderlo anche perché non possiamo lasciarlo aperto. Pertanto, dopo aver creato un socket, abbiamo bisogno di un metodo per chiudere il socket nel codice una volta terminato il lavoro. Questo metodo close chiuderà il socket che rappresenta i dati allegati per motivi di sicurezza.

I passi da seguire

Riassumendo riportiamo brevemente i passaggi menzionati che è necessario seguire per la programmazione dei Socket in C++.

  • Creare il socket fornendo dominio, tipo e protocollo.
  • Possiamo usare Setsockopted se abbiamo bisogno di riutilizzare l’indirizzo e la porta. È facoltativo.
  • Una volta creato il socket, viene utilizzato il metodo Bind per associare il socket all’indirizzo e al numero di porta specificati nella struttura dati personalizzata.
  • Il metodo listen viene utilizzato per mantenere il socket inattivo quando attende che venga stabilita la connessione client-server.
  • Il metodo Accept avrà la prima richiesta di connessione nell’elenco delle connessioni in sospeso nel socket. Poiché creerà un nuovo socket già connesso e restituirà un nuovo descrittore di file. Questo è il punto di contatto tra server e client in cui il tuo socket è pronto per il trasferimento dei dati.

Esempi di programmazione dei socket in C++: Socket client

Poiché il socket ha solitamente due parti, una è il client e l’altra è il server. Analizziamoli entrambi nel dettaglio dell’esempio che segue:

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define PORT 8080
int main ( int argument, char const *argv[] )
{
int obj_socket = 0, reader;
struct sockaddr_in serv_addr;
char *message = (char*) "Un messaggio dal Client!";
char buffer[1024] = {0};
if (( obj_socket = socket (AF_INET, SOCK_STREAM, 0 )) < 0)
{
printf ( "Errore nella creazione del Socket!" );
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Converte gli indirizzi IPv4 e IPv6 da testo a binario
if(inet_pton ( AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
{
printf ( "\nIndirizzo non valido! Questo Indirizzo IP non è supportato!\n" );
return -1;
}
if ( connect( obj_socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr )) < 0)
{
printf ( "Connessione Fallita: Non posso stabilire una connessione a questo socket!" );
return -1;
}
send ( obj_socket , message , strlen(message) , 0 );
printf ( "\nClient : Il Messaggio è stato inviato!\n" );
reader = read ( obj_socket, buffer, 1024 );
printf ( "%s\n",buffer );
return 0;
}

Esempi di programmazione dei socket in C++: Socket server

Di seguito è riportato il programma in C++ per testare la programmazione socket sul lato server. Si osservi che ovviamente bisogna avviare prima la parte server dellla procedura e poi la parte client per evitare l’errore di connessione non riuscita!

#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <stdlib.h>
#define PORT 8080
int main ( int argument, char const *argv[] )
{
int obj_server, sock, reader;
struct sockaddr_in address;
int opted = 1;
int address_length = sizeof(address);
char buffer[1024] = {0};
char *message = (char*) "Un Messaggio dal Server!!";
if (( obj_server = socket ( AF_INET, SOCK_STREAM, 0)) == 0)
{
perror ( "Apertura del Socket Fallita!");
exit ( EXIT_FAILURE);
}
if ( setsockopt(obj_server, SOL_SOCKET, SO_REUSEADDR,
&opted, sizeof ( opted )))
{
perror ( "Impossibile impostare il socket" );
exit ( EXIT_FAILURE );
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
if (bind(obj_server, ( struct sockaddr * )&address,
sizeof(address))<0)
{
perror ( "Associazione del Socket non riuscita!" );
exit(EXIT_FAILURE);
}
if (listen ( obj_server, 3) < 0)
{
perror ( "Impossibile ascoltare dal server!");
exit(EXIT_FAILURE);
}
if ((sock = accept(obj_server, (struct sockaddr *)&address, (socklen_t*)&address_length)) < 0)
{
perror("Accept");
exit(EXIT_FAILURE);
}
reader = read(sock, buffer, 1024);
printf("%s\n", buffer);
send(sock , message, strlen(message) , 0 );
printf("Server : Il Messaggio è stato inviato! \n");
return 0;
}

Considerazioni finali

Abbiamo visto in questo articolo due script scritti con il linguaggio C++ e la programmazione dei socket. Ricordiamo, come già fatto, che è importante avviare prima la parte Server e poi la parte Client. Il codice è stato provato con XCode per Mac OSX 13.1 Ricordiamo che questo Portale ha tutta una sezione riservata alla Programmazione. In questa sezione oltre a tanti esempi di codice, troverete anche strumenti utili per la programmazione come Framework, librerie e tanto altro.