Gniazdo Unix - podstawowe funkcje

W tym rozdziale opisano podstawowe funkcje gniazda wymagane do napisania kompletnego klienta i serwera TCP.

Poniższy diagram przedstawia pełną interakcję klienta i serwera -

Funkcja gniazda

Aby wykonać operacje we / wy sieci, pierwszą rzeczą, jaką musi wykonać proces, jest wywołanie funkcji gniazda, określenie typu żądanego protokołu komunikacyjnego i rodziny protokołów itp.

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

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

To wywołanie zwraca deskryptor gniazda, którego można użyć w późniejszych wywołaniach systemowych lub -1 w przypadku błędu.

Parametry

family - Określa rodzinę protokołów i jest jedną ze stałych pokazanych poniżej -

Rodzina Opis
AF_INET Protokoły IPv4
AF_INET6 Protokoły IPv6
AF_LOCAL Protokoły domeny Unix
AF_ROUTE Gniazda routingu
AF_KEY Gniazdo Ket

W tym rozdziale nie omówiono innych protokołów z wyjątkiem IPv4.

type- Określa rodzaj gniazda, które chcesz. Może przyjąć jedną z następujących wartości -

Rodzaj Opis
SOCK_STREAM Gniazdo strumieniowe
SOCK_DGRAM Gniazdo datagramowe
SOCK_SEQPACKET Sekwencyjne gniazdo pakietów
SOCK_RAW Gniazdo surowe

protocol - Argument powinien być ustawiony na konkretny typ protokołu podany poniżej lub 0, aby wybrać domyślny system dla danej kombinacji rodziny i typu -

Protokół Opis
IPPROTO_TCP Protokół transportowy TCP
IPPROTO_UDP Protokół transportowy UDP
IPPROTO_SCTP Protokół transportowy SCTP

Connect Function

Funkcja connect jest używana przez klienta TCP do nawiązywania połączenia z serwerem TCP.

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

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

To wywołanie zwraca 0, jeśli pomyślnie łączy się z serwerem, w przeciwnym razie zwraca -1 w przypadku błędu.

Parametry

  • sockfd - Jest to deskryptor gniazda zwracany przez funkcję gniazda.

  • serv_addr - Jest to wskaźnik do struct sockaddr, który zawiera docelowy adres IP i port.

  • addrlen - Ustaw na sizeof (struct sockaddr).

Wiążą Function

Funkcja bind przypisuje adres protokołu lokalnego do gniazda. W przypadku protokołów internetowych adres protokołu to kombinacja 32-bitowego adresu IPv4 lub 128-bitowego adresu IPv6 wraz z 16-bitowym numerem portu TCP lub UDP. Ta funkcja jest wywoływana tylko przez serwer TCP.

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

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

To wywołanie zwraca 0, jeśli pomyślnie połączy się z adresem, w przeciwnym razie zwraca -1 w przypadku błędu.

Parametry

  • sockfd - Jest to deskryptor gniazda zwracany przez funkcję gniazda.

  • my_addr - Jest to wskaźnik do struct sockaddr, który zawiera lokalny adres IP i port.

  • addrlen - Ustaw na sizeof (struct sockaddr).

Możesz automatycznie umieścić swój adres IP i port

Wartość 0 dla numeru portu oznacza, że ​​system wybierze losowy port, a wartość INADDR_ANY dla adresu IP oznacza, że ​​adres IP serwera zostanie przypisany automatycznie.

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

NOTE- Wszystkie porty poniżej 1024 są zarezerwowane. Możesz ustawić port powyżej 1024 i poniżej 65535, chyba że są one używane przez inne programy.

Słuchać funkcji

Funkcja nasłuchiwania jest wywoływana tylko przez serwer TCP i wykonuje dwie czynności -

  • Funkcja Listen przekształca niepołączone gniazdo w gniazdo pasywne, wskazując, że jądro powinno akceptować przychodzące żądania połączeń kierowane do tego gniazda.

  • Drugi argument tej funkcji określa maksymalną liczbę połączeń, jakie jądro powinno kolejkować dla tego gniazda.

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

int listen(int sockfd,int backlog);

To wywołanie zwraca 0 w przypadku sukcesu, w przeciwnym razie zwraca -1 w przypadku błędu.

Parametry

  • sockfd - Jest to deskryptor gniazda zwracany przez funkcję gniazda.

  • backlog - Jest to liczba dozwolonych połączeń.

Przyjąć funkcji

Funkcja accept jest wywoływana przez serwer TCP w celu zwrócenia następnego ukończonego połączenia z przodu kolejki zakończonych połączeń. Podpis wezwania jest następujący -

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

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

To wywołanie zwraca nieujemny deskryptor w przypadku sukcesu, w przeciwnym razie zwraca -1 w przypadku błędu. Przyjmuje się, że zwrócony deskryptor jest deskryptorem gniazda klienta i wszystkie operacje odczytu i zapisu będą wykonywane na tym deskryptorze w celu komunikacji z klientem.

Parametry

  • sockfd - Jest to deskryptor gniazda zwracany przez funkcję gniazda.

  • cliaddr - Jest to wskaźnik do struct sockaddr, który zawiera adres IP i port klienta.

  • addrlen - Ustaw na sizeof (struct sockaddr).

Wyślij Function

Funkcja wysyłania służy do wysyłania danych przez gniazda strumieniowe lub gniazda datagramowe CONNECTED. Jeśli chcesz wysyłać dane przez NIEPODŁĄCZONE gniazda datagramowe, musisz użyć funkcji sendto ().

Możesz użyć wywołania systemowego write () do wysyłania danych. Jego podpis jest następujący -

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

To wywołanie zwraca liczbę wysłanych bajtów, w przeciwnym razie zwróci -1 w przypadku błędu.

Parametry

  • sockfd - Jest to deskryptor gniazda zwracany przez funkcję gniazda.

  • msg - Jest to wskaźnik do danych, które chcesz wysłać.

  • len - Jest to długość danych, które chcesz wysłać (w bajtach).

  • flags - Jest ustawiony na 0.

Recv Function

Funkcja recv służy do odbierania danych przez gniazda strumieniowe lub gniazda datagramowe CONNECTED. Jeśli chcesz otrzymywać dane przez NIEPODŁĄCZONE gniazda datagramowe, musisz użyć funkcji recvfrom ().

Do odczytania danych można użyć wywołania systemowego read () . To wywołanie jest wyjaśnione w rozdziale o funkcjach pomocniczych.

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

To wywołanie zwraca liczbę bajtów wczytanych do bufora, w przeciwnym razie zwróci -1 w przypadku błędu.

Parametry

  • sockfd - Jest to deskryptor gniazda zwracany przez funkcję gniazda.

  • buf - Jest to bufor do wczytywania informacji.

  • len - Jest to maksymalna długość bufora.

  • flags - Jest ustawiony na 0.

Sendto Function

Funkcja sendto służy do wysyłania danych przez NIEPODŁĄCZONE gniazda datagramowe. Jego podpis jest następujący -

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

To wywołanie zwraca liczbę wysłanych bajtów, w przeciwnym razie zwraca -1 w przypadku błędu.

Parametry

  • sockfd - Jest to deskryptor gniazda zwracany przez funkcję gniazda.

  • msg - Jest to wskaźnik do danych, które chcesz wysłać.

  • len - Jest to długość danych, które chcesz wysłać (w bajtach).

  • flags - Jest ustawiony na 0.

  • to - Jest to wskaźnik struct sockaddr dla hosta, do którego mają zostać wysłane dane.

  • tolen - Jest ustawiony na sizeof (struct sockaddr).

Recvfrom Function

Funkcja recvfrom służy do odbierania danych z gniazd datagramowych UNCONNECTED.

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

To wywołanie zwraca liczbę bajtów wczytanych do bufora, w przeciwnym razie zwraca -1 w przypadku błędu.

Parametry

  • sockfd - Jest to deskryptor gniazda zwracany przez funkcję gniazda.

  • buf - Jest to bufor do wczytywania informacji.

  • len - Jest to maksymalna długość bufora.

  • flags - Jest ustawiony na 0.

  • from - Jest to wskaźnik struct sockaddr dla hosta, z którego mają zostać odczytane dane.

  • fromlen - Jest ustawiony na sizeof (struct sockaddr).

Blisko Function

Funkcja close służy do zamykania komunikacji między klientem a serwerem. Jego składnia jest następująca -

int close( int sockfd );

To wywołanie zwraca 0 w przypadku sukcesu, w przeciwnym razie zwraca -1 w przypadku błędu.

Parametry

  • sockfd - Jest to deskryptor gniazda zwracany przez funkcję gniazda.

Wyłączanie funkcji

Funkcja zamykania służy do bezpiecznego zamykania komunikacji między klientem a serwerem. Ta funkcja zapewnia większą kontrolę w porównaniu z funkcją zamykania . Poniżej podano składnię shutdown -

int shutdown(int sockfd, int how);

To wywołanie zwraca 0 w przypadku sukcesu, w przeciwnym razie zwraca -1 w przypadku błędu.

Parametry

  • sockfd - Jest to deskryptor gniazda zwracany przez funkcję gniazda.

  • how - Wpisz jedną z liczb -

    • 0 - wskazuje, że odbieranie jest niedozwolone,

    • 1 - wskazuje, że wysyłanie jest niedozwolone i

    • 2- wskazuje, że zarówno wysyłanie, jak i odbieranie nie są dozwolone. Gdy jak jest ustawione na 2, jest to to samo, co close ().

Select Function

Funkcja select wskazuje, który z określonych deskryptorów plików jest gotowy do odczytu, gotowy do zapisu lub ma oczekujący stan błędu.

Gdy aplikacja wywołuje recv lub recvfrom , jest blokowana do momentu nadejścia danych do tego gniazda. Aplikacja może wykonywać inne przydatne operacje, gdy strumień danych przychodzących jest pusty. Inna sytuacja ma miejsce, gdy aplikacja otrzymuje dane z wielu gniazd.

Wywołanie recv lub recvfrom w gnieździe, które nie ma danych w swojej kolejce wejściowej, zapobiega natychmiastowemu otrzymywaniu danych z innych gniazd. Wywołanie funkcji select rozwiązuje ten problem, umożliwiając programowi odpytywanie wszystkich uchwytów gniazd w celu sprawdzenia, czy są one dostępne dla nieblokujących operacji odczytu i zapisu.

Poniżej podano składnię select -

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

To wywołanie zwraca 0 w przypadku sukcesu, w przeciwnym razie zwraca -1 w przypadku błędu.

Parametry

  • nfds- Określa zakres deskryptorów plików do przetestowania. Funkcja select () testuje deskryptory plików w zakresie od 0 do nfds-1

  • readfds- Wskazuje na obiekt typu fd_set, który na wejściu określa deskryptory plików, które mają być sprawdzane pod kątem gotowości do odczytu, a na wyjściu wskazuje, które deskryptory plików są gotowe do odczytu. Może mieć wartość NULL, aby wskazać pusty zestaw.

  • writefds- Wskazuje na obiekt typu fd_set, który na wejściu określa deskryptory plików do sprawdzenia pod kątem gotowości do zapisu, a na wyjściu wskazuje, które deskryptory plików są gotowe do zapisu. Może mieć wartość NULL, aby wskazać pusty zestaw.

  • exceptfds- Wskazuje na obiekt typu fd_set, który na wejściu określa deskryptory plików, które mają być sprawdzane pod kątem oczekujących warunków błędu, a na wyjściu wskazuje, które deskryptory plików mają oczekujące warunki błędu. Może mieć wartość NULL, aby wskazać pusty zestaw.

  • timeout- Wskazuje na strukturę timeval, która określa, jak długo wywołanie select powinno odpytywać deskryptory pod kątem dostępnej operacji we / wy. Jeśli wartość limitu czasu wynosi 0, select natychmiast zwróci. Jeśli argument timeout ma wartość NULL, select będzie blokować, dopóki co najmniej jeden uchwyt pliku / gniazda nie będzie gotowy na dostępną operację we / wy. W przeciwnym razie funkcja select zwróci wartość po upływie określonego czasu LUB gdy co najmniej jeden deskryptor pliku / gniazda jest gotowy do operacji we / wy.

Wartość zwracana z select to liczba uchwytów określonych w zestawach deskryptorów plików, które są gotowe do operacji we / wy. Jeśli zostanie osiągnięty limit czasu określony przez pole limitu czasu, wybierz opcję powrotu 0. Istnieją następujące makra służące do manipulowania zestawem deskryptorów plików -

  • FD_CLR(fd, &fdset)- Czyści bit dla deskryptora pliku fd w zestawie deskryptorów pliku fdset.

  • FD_ISSET(fd, &fdset)- Zwraca wartość niezerową, jeśli bit deskryptora pliku fd jest ustawiony w deskryptorze pliku wskazywanym przez fdset , a 0 w przeciwnym razie.

  • FD_SET(fd, &fdset) - Ustawia bit dla deskryptora pliku fd w zestawie deskryptorów pliku fdset.

  • FD_ZERO(&fdset) - Inicjuje zestaw deskryptorów plików fdset tak, aby miał zero bitów dla wszystkich deskryptorów plików.

Zachowanie tych makr jest niezdefiniowane, jeśli argument fd jest mniejszy niż 0 lub większy lub równy FD_SETSIZE.

Przykład

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 */
}