📢 Nuovo Corso Laravel API disponibile!

Networking Base in C

Il networking è una parte fondamentale della programmazione moderna, permettendo la comunicazione tra processi su reti locali o su Internet. In C, la creazione di connessioni di rete avviene principalmente attraverso l’uso di socket, che rappresentano un punto finale di comunicazione. In questa guida, esploreremo i concetti base del networking in C, compreso come creare, gestire e chiudere socket per realizzare semplici applicazioni client-server.

Cos’è un Socket?

Un socket è un’interfaccia che consente a un processo di inviare e ricevere dati su una rete. I socket possono essere utilizzati per implementare diversi protocolli di rete, tra cui TCP (Transmission Control Protocol) e UDP (User Datagram Protocol).

Tipi di Socket

  • Socket TCP: Forniscono una connessione affidabile e orientata al flusso, con garanzia di consegna dei dati.
  • Socket UDP: Offrono una connessione non affidabile e basata su datagrammi, senza garanzia di consegna.

Creazione di un Socket

Per creare un socket in C, utilizziamo la funzione socket().

Sintassi di socket()

int socket(int domain, int type, int protocol);
  • domain: Specifica il dominio di comunicazione. Per esempio, AF_INET per IPv4.
  • type: Specifica il tipo di socket. Per esempio, SOCK_STREAM per TCP o SOCK_DGRAM per UDP.
  • protocol: Specifica il protocollo. Solitamente impostato a 0 per usare il protocollo predefinito.

Esempio di Creazione di un Socket TCP

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main() {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("Errore nella creazione del socket");
exit(EXIT_FAILURE);
}
printf("Socket creato con successo!\n");
close(sockfd);
return 0;
}

Uscita:

Socket creato con successo!

Creazione di un Server TCP

Un server TCP inizia creando un socket, quindi lo lega (bind) a un indirizzo e porta specifici, lo ascolta (listen) per le connessioni in arrivo e accetta (accept) le connessioni da parte dei client.

Passi per Creare un Server TCP

  1. Creare il socket con socket().
  2. Associare il socket a un indirizzo IP e una porta con bind().
  3. Ascoltare le connessioni in arrivo con listen().
  4. Accettare una connessione in entrata con accept().
  5. Comunicare con il client usando send() e recv().

Esempio di Server TCP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[1024] = {0};
char *hello = "Hello from server";
// Creazione del socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("Errore nella creazione del socket");
exit(EXIT_FAILURE);
}
// Assegnazione dell'indirizzo al socket
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("Errore nel binding");
close(server_fd);
exit(EXIT_FAILURE);
}
// Ascolto delle connessioni in arrivo
if (listen(server_fd, 3) < 0) {
perror("Errore nell'ascolto");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("In attesa di connessioni...\n");
// Accettazione di una connessione
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("Errore nell'accettazione");
close(server_fd);
exit(EXIT_FAILURE);
}
// Comunicazione con il client
read(new_socket, buffer, 1024);
printf("Messaggio ricevuto: %s\n", buffer);
send(new_socket, hello, strlen(hello), 0);
printf("Messaggio inviato: %s\n", hello);
close(new_socket);
close(server_fd);
return 0;
}

Uscita:

In attesa di connessioni...
Messaggio ricevuto: Hello from client
Messaggio inviato: Hello from server

Creazione di un Client TCP

Un client TCP crea un socket, si connette a un server specificando l’indirizzo IP e la porta, quindi invia e riceve dati attraverso il socket.

Passi per Creare un Client TCP

  1. Creare il socket con socket().
  2. Connettersi al server con connect().
  3. Comunicare con il server usando send() e recv().

Esempio di Client TCP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[1024] = {0};
// Creazione del socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("Errore nella creazione del socket\n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
// Convertire l'indirizzo IP da testo a binario
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("Indirizzo non valido\n");
return -1;
}
// Connessione al server
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("Connessione fallita\n");
return -1;
}
// Comunicazione con il server
send(sock, hello, strlen(hello), 0);
printf("Messaggio inviato: %s\n", hello);
read(sock, buffer, 1024);
printf("Messaggio ricevuto: %s\n", buffer);
close(sock);
return 0;
}

Uscita:

Messaggio inviato: Hello from client
Messaggio ricevuto: Hello from server

Networking con UDP

Con UDP, non c’è una connessione stabile tra client e server, quindi i dati sono inviati come pacchetti singoli. Le funzioni principali rimangono le stesse, ma con alcune differenze nell’uso di sendto e recvfrom invece di send e recv.

Esempio di Server UDP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int sockfd;
char buffer[1024];
char *hello = "Hello from server";
struct sockaddr_in servaddr, cliaddr;
// Creazione del socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("Errore nella creazione del socket");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Assegnazione dell'indirizzo al socket
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(8080);
if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("Errore nel binding");
close(sockfd);
exit(EXIT_FAILURE);
}
int len, n;
len = sizeof(cliaddr);
// Ricezione di un messaggio dal client
n = recvfrom(sockfd, buffer, 1024, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len);
buffer[n] = '\0';
printf("Messaggio ricevuto: %s\n", buffer);
// Inviare una risposta al client
sendto(sockfd, hello, strlen(hello), MSG_CONFIRM, (const struct sockaddr *)&cliaddr, len);
printf("Messaggio
inviato: %s\n", hello);
close(sockfd);
return 0;
}

Esempio di Client UDP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int sockfd;
char *hello = "Hello from client";
char buffer[1024];
struct sockaddr_in servaddr;
// Creazione del socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("Errore nella creazione del socket");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8080);
servaddr.sin_addr.s_addr = INADDR_ANY;
// Inviare un messaggio al server
sendto(sockfd, hello, strlen(hello), MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr));
printf("Messaggio inviato: %s\n", hello);
int n, len;
len = sizeof(servaddr);
// Ricezione della risposta dal server
n = recvfrom(sockfd, buffer, 1024, MSG_WAITALL, (struct sockaddr *)&servaddr, &len);
buffer[n] = '\0';
printf("Messaggio ricevuto: %s\n", buffer);
close(sockfd);
return 0;
}

Uscita:

Messaggio inviato: Hello from client
Messaggio ricevuto: Hello from server

Conclusioni

Il networking in C è una competenza fondamentale per sviluppare applicazioni che richiedono la comunicazione tra diversi dispositivi su una rete. Comprendere come creare, configurare e utilizzare socket per la comunicazione TCP e UDP è essenziale per costruire server e client robusti e affidabili. Con pratica e sperimentazione, sarai in grado di affrontare progetti di networking sempre più complessi, sfruttando la potenza e la flessibilità del linguaggio C.