Unix Socket - Funzioni principali

Questo capitolo descrive le funzioni principali del socket richieste per scrivere un client e un server TCP completo.

Il diagramma seguente mostra l'intera interazione tra client e server:

La funzione socket

Per eseguire l'I / O di rete, la prima cosa che un processo deve fare è chiamare la funzione socket, specificando il tipo di protocollo di comunicazione desiderato e la famiglia di protocolli, ecc.

#include <sys/types.h>
#include <sys/socket.h>

int socket (int family, int type, int protocol);

Questa chiamata restituisce un descrittore di socket che puoi utilizzare nelle chiamate di sistema successive o -1 in caso di errore.

Parametri

family - Specifica la famiglia di protocollo ed è una delle costanti mostrate di seguito -

Famiglia Descrizione
AF_INET Protocolli IPv4
AF_INET6 Protocolli IPv6
AF_LOCAL Protocolli di dominio Unix
AF_ROUTE Prese di instradamento
AF_KEY Presa Ket

Questo capitolo non copre altri protocolli eccetto IPv4.

type- Specifica il tipo di presa che desideri. Può assumere uno dei seguenti valori:

genere Descrizione
SOCK_STREAM Presa di flusso
SOCK_DGRAM Presa datagramma
SOCK_SEQPACKET Presa pacchetto sequenziale
SOCK_RAW Presa grezza

protocol - L'argomento deve essere impostato sul tipo di protocollo specifico indicato di seguito, o 0 per selezionare l'impostazione predefinita del sistema per la data combinazione di famiglia e tipo -

Protocollo Descrizione
IPPROTO_TCP Protocollo di trasporto TCP
IPPROTO_UDP Protocollo di trasporto UDP
IPPROTO_SCTP Protocollo di trasporto SCTP

La funzione di connessione

La funzione di connessione viene utilizzata da un client TCP per stabilire una connessione con un server TCP.

#include <sys/types.h>
#include <sys/socket.h>

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

Questa chiamata restituisce 0 se si connette correttamente al server, altrimenti restituisce -1 in caso di errore.

Parametri

  • sockfd - È un descrittore di socket restituito dalla funzione socket.

  • serv_addr - È un puntatore a struct sockaddr che contiene l'indirizzo IP e la porta di destinazione.

  • addrlen - Impostalo su sizeof (struct sockaddr).

La funzione bind

La funzione bind assegna un indirizzo di protocollo locale a un socket. Con i protocolli Internet, l'indirizzo del protocollo è la combinazione di un indirizzo IPv4 a 32 bit o di un indirizzo IPv6 a 128 bit, insieme a un numero di porta TCP o UDP a 16 bit. Questa funzione viene chiamata solo dal server TCP.

#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, struct sockaddr *my_addr,int addrlen);

Questa chiamata restituisce 0 se si collega correttamente all'indirizzo, altrimenti restituisce -1 in caso di errore.

Parametri

  • sockfd - È un descrittore di socket restituito dalla funzione socket.

  • my_addr - È un puntatore a struct sockaddr che contiene l'indirizzo IP e la porta locali.

  • addrlen - Impostalo su sizeof (struct sockaddr).

Puoi inserire automaticamente il tuo indirizzo IP e la tua porta

Un valore 0 per il numero di porta significa che il sistema sceglierà una porta casuale e il valore INADDR_ANY per l'indirizzo IP significa che l'indirizzo IP del server verrà assegnato automaticamente.

server.sin_port = 0;  		     
server.sin_addr.s_addr = INADDR_ANY;

NOTE- Tutte le porte inferiori a 1024 sono riservate. È possibile impostare una porta superiore a 1024 e inferiore a 65535 a meno che non siano quelle utilizzate da altri programmi.

La funzione di ascolto

La funzione di ascolto viene chiamata solo da un server TCP ed esegue due azioni:

  • La funzione di ascolto converte un socket non connesso in un socket passivo, indicando che il kernel dovrebbe accettare le richieste di connessione in entrata dirette a questo socket.

  • Il secondo argomento di questa funzione specifica il numero massimo di connessioni che il kernel deve mettere in coda per questo socket.

#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd,int backlog);

Questa chiamata restituisce 0 in caso di successo, altrimenti restituisce -1 in caso di errore.

Parametri

  • sockfd - È un descrittore di socket restituito dalla funzione socket.

  • backlog - È il numero di connessioni consentite.

La funzione di accettazione

La funzione di accettazione viene chiamata da un server TCP per restituire la successiva connessione completata dalla parte anteriore della coda di connessione completata. La firma della chiamata è la seguente:

#include <sys/types.h>
#include <sys/socket.h>

int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

Questa chiamata restituisce un descrittore non negativo in caso di successo, altrimenti restituisce -1 in caso di errore. Si presume che il descrittore restituito sia un descrittore di socket client e tutte le operazioni di lettura-scrittura verranno eseguite su questo descrittore per comunicare con il client.

Parametri

  • sockfd - È un descrittore di socket restituito dalla funzione socket.

  • cliaddr - È un puntatore a struct sockaddr che contiene l'indirizzo IP e la porta del client.

  • addrlen - Impostalo su sizeof (struct sockaddr).

La funzione di invio

La funzione di invio viene utilizzata per inviare dati tramite stream socket o socket datagram CONNECTED. Se si desidera inviare dati su socket datagrammi NON CONNESSI, è necessario utilizzare la funzione sendto ().

È possibile utilizzare la chiamata di sistema write () per inviare i dati. La sua firma è la seguente:

int send(int sockfd, const void *msg, int len, int flags);

Questa chiamata restituisce il numero di byte inviati, altrimenti restituirà -1 in caso di errore.

Parametri

  • sockfd - È un descrittore di socket restituito dalla funzione socket.

  • msg - È un puntatore ai dati che vuoi inviare.

  • len - È la lunghezza dei dati che vuoi inviare (in byte).

  • flags - È impostato a 0.

La funzione recv

La funzione recv viene utilizzata per ricevere dati su stream socket o socket datagram CONNECTED. Se vuoi ricevere dati su socket datagram UNCONNECTED devi usare recvfrom ().

È possibile utilizzare la chiamata di sistema read () per leggere i dati. Questa chiamata è spiegata nel capitolo sulle funzioni di supporto.

int recv(int sockfd, void *buf, int len, unsigned int flags);

Questa chiamata restituisce il numero di byte letti nel buffer, altrimenti restituirà -1 in caso di errore.

Parametri

  • sockfd - È un descrittore di socket restituito dalla funzione socket.

  • buf - È il buffer in cui leggere le informazioni.

  • len - È la lunghezza massima del buffer.

  • flags - È impostato a 0.

La funzione sendto

La funzione sendto viene utilizzata per inviare dati su socket di datagramma NON CONNESSI. La sua firma è la seguente:

int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);

Questa chiamata restituisce il numero di byte inviati, altrimenti restituisce -1 in caso di errore.

Parametri

  • sockfd - È un descrittore di socket restituito dalla funzione socket.

  • msg - È un puntatore ai dati che vuoi inviare.

  • len - È la lunghezza dei dati che vuoi inviare (in byte).

  • flags - È impostato a 0.

  • to - È un puntatore a struct sockaddr per l'host a cui devono essere inviati i dati.

  • tolen - È impostato su sizeof (struct sockaddr).

La funzione recvfrom

La funzione recvfrom viene utilizzata per ricevere dati da socket di datagramma UNCONNECTED.

int recvfrom(int sockfd, void *buf, int len, unsigned int flags struct sockaddr *from, int *fromlen);

Questa chiamata restituisce il numero di byte letti nel buffer, altrimenti restituisce -1 in caso di errore.

Parametri

  • sockfd - È un descrittore di socket restituito dalla funzione socket.

  • buf - È il buffer in cui leggere le informazioni.

  • len - È la lunghezza massima del buffer.

  • flags - È impostato a 0.

  • from - È un puntatore a struct sockaddr per l'host in cui i dati devono essere letti.

  • fromlen - È impostato su sizeof (struct sockaddr).

La funzione di chiusura

La funzione di chiusura viene utilizzata per chiudere la comunicazione tra il client e il server. La sua sintassi è la seguente:

int close( int sockfd );

Questa chiamata restituisce 0 in caso di successo, altrimenti restituisce -1 in caso di errore.

Parametri

  • sockfd - È un descrittore di socket restituito dalla funzione socket.

La funzione di spegnimento

La funzione di arresto viene utilizzata per chiudere normalmente la comunicazione tra il client e il server. Questa funzione offre un maggiore controllo rispetto alla funzione di chiusura . Di seguito è riportata la sintassi dell'arresto :

int shutdown(int sockfd, int how);

Questa chiamata restituisce 0 in caso di successo, altrimenti restituisce -1 in caso di errore.

Parametri

  • sockfd - È un descrittore di socket restituito dalla funzione socket.

  • how - Metti uno dei numeri -

    • 0 - indica che la ricezione non è consentita,

    • 1 - indica che l'invio non è consentito e

    • 2- indica che sia l'invio che la ricezione non sono consentiti. Quando how è impostato su 2, è la stessa cosa di close ().

La funzione di selezione

La funzione di selezione indica quale dei descrittori di file specificati è pronto per la lettura, pronto per la scrittura o ha una condizione di errore in sospeso.

Quando un'applicazione chiama recv o recvfrom , viene bloccata finché non arrivano dati per quel socket. Un'applicazione potrebbe eseguire altre elaborazioni utili mentre il flusso di dati in entrata è vuoto. Un'altra situazione è quando un'applicazione riceve dati da più socket.

La chiamata di recv o recvfrom su un socket che non ha dati nella sua coda di input impedisce la ricezione immediata di dati da altri socket. La chiamata alla funzione select risolve questo problema consentendo al programma di interrogare tutti gli handle del socket per vedere se sono disponibili per operazioni di lettura e scrittura non bloccanti.

Di seguito è riportata la sintassi di select -

int select(int  nfds, fd_set  *readfds, fd_set  *writefds, fd_set *errorfds, struct timeval *timeout);

Questa chiamata restituisce 0 in caso di successo, altrimenti restituisce -1 in caso di errore.

Parametri

  • nfds- Specifica la gamma di descrittori di file da testare. La funzione select () verifica i descrittori di file nell'intervallo da 0 a nfds-1

  • readfds- Punta a un oggetto di tipo fd_set che in input specifica i descrittori di file da controllare per essere pronti per la lettura e in output indica quali descrittori di file sono pronti per la lettura. Può essere NULL per indicare un set vuoto.

  • writefds- Punta a un oggetto di tipo fd_set che in input specifica i descrittori di file da controllare per essere pronti per la scrittura e in output indica quali descrittori di file sono pronti per la scrittura. Può essere NULL per indicare un set vuoto.

  • exceptfds- Punta a un oggetto di tipo fd_set che in input specifica i descrittori di file da controllare per le condizioni di errore in sospeso e in output indica quali descrittori di file hanno condizioni di errore in sospeso. Può essere NULL per indicare un set vuoto.

  • timeout- Punta a una struttura temporale che specifica per quanto tempo la chiamata select deve interrogare i descrittori per un'operazione di I / O disponibile. Se il valore di timeout è 0, select tornerà immediatamente. Se l'argomento timeout è NULL, select si bloccherà fino a quando almeno un handle di file / socket sarà pronto per un'operazione di I / O disponibile. In caso contrario, select tornerà dopo che è trascorso il tempo nel timeout O quando almeno un descrittore di file / socket è pronto per un'operazione di I / O.

Il valore restituito da select è il numero di handle specificati nei set di descrittori di file pronti per l'I / O. Se viene raggiunto il limite di tempo specificato dal campo timeout, selezionare return 0. Esistono le seguenti macro per manipolare un set di descrittori di file:

  • FD_CLR(fd, &fdset)- Cancella il bit per il descrittore di file fd nel descrittore di file impostato fdset.

  • FD_ISSET(fd, &fdset)- Restituisce un valore diverso da zero se il bit per il descrittore di file fd è impostato nel set di descrittori di file puntato da fdset , e 0 altrimenti.

  • FD_SET(fd, &fdset) - Imposta il bit per il descrittore di file fd nel descrittore di file impostato fdset.

  • FD_ZERO(&fdset) - Inizializza il descrittore di file impostato fdset in modo che abbia zero bit per tutti i descrittori di file.

Il comportamento di queste macro non è definito se l'argomento fd è minore di 0 o maggiore o uguale a FD_SETSIZE.

Esempio

fd_set fds;

struct timeval tv;

/* do socket initialization etc.
tv.tv_sec = 1;
tv.tv_usec = 500000;

/* tv now represents 1.5 seconds */
FD_ZERO(&fds);

/* adds sock to the file descriptor set */
FD_SET(sock, &fds); 

/* wait 1.5 seconds for any data to be read from any single socket */
select(sock+1, &fds, NULL, NULL, &tv);

if (FD_ISSET(sock, &fds)) {
   recvfrom(s, buffer, buffer_len, 0, &sa, &sa_len);
   /* do something */
}
else {
   /* do something else */
}