Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Books
  Краткое описание
 Linux
 W. R. Стивенс TCP 
 W. R. Стивенс IPC 
 A.Rubini-J.Corbet 
 K. Bauer 
 Gary V. Vaughan 
 Д Вилер 
 В. Сталлинг 
 Pramode C.E. 
 Steve Pate 
 William Gropp 
 K.A.Robbins 
 С Бекман 
 Р Стивенс 
 Ethereal 
 Cluster 
 Languages
 C
 Perl
 M.Pilgrim 
 А.Фролов 
 Mendel Cooper 
 М Перри 
 Kernel
 C.S. Rodriguez 
 Robert Love 
 Daniel Bovet 
 Д Джеф 
 Максвелл 
 G. Kroah-Hartman 
 B. Hansen 
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Linux Kernel 2.6...5164 
 Trees...935 
 Максвелл 3...861 
 Go Web ...814 
 William Gropp...795 
 Ethreal 3...779 
 Ethreal 4...766 
 Gary V.Vaughan-> Libtool...764 
 Rodriguez 6...755 
 Clickhouse...748 
 Steve Pate 1...748 
 Ext4 FS...748 
 Ethreal 1...736 
 Secure Programming for Li...718 
 C++ Patterns 3...711 
 Ulrich Drepper...692 
 Assembler...686 
 DevFS...654 
 Стивенс 9...644 
 MySQL & PosgreSQL...621 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

 W. R. Stevens  : Глава 3

Введение в сокеты

Сокет можно передавать в 2-х направлениях : от процесса к ядру и от ядра к процессу. Текстовое представление адреса сокета в двоичное выполняют функции inet_addr и inet_ntoa, эти 2 функции работают в IPv4. Еще 2 функции - inet_pton и inet_ntop - работают как в IPv4 , так и в IPv6.

Большинство функций сокетов используют в качестве аргумента указатель на структуру адреса сокета. Каждый набор протоколов определяет свою собственную структуру адреса сокета. Имена этих структур начинаются с sockaddr_ и заканчиваются уникальным суффиксом.

Структура адреса сокета IPv4 - sockaddr_in :


 struct in_addr {
 	in_addr_t s_addr;
 				};
 struct sockaddr_in {
 	uint8_t  		sin_len;
 	sa_family_t 	sin_family;
 	in_port_t 		sin_port;
 	struct in_addr  sin_addr;
 	char 			sin_zero[8];
 					};
 

 Например  , в 10-й SUSE это прописано в /include/linux/in.h :
 struct in_addr {
         __u32   s_addr;
 };
 struct sockaddr_in {
   sa_family_t           sin_family;     /* Address family               */
   unsigned short int    sin_port;       /* Port number                  */
   struct in_addr        sin_addr;       /* Internet address             */
 
   /* Pad to size of `struct sockaddr'. */
   unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -
                         sizeof(unsigned short int) - sizeof(struct in_addr)];
 };
 Поле sin_len здесь просто не поддерживается. Если даже оно и присутствует , его не обязательно инициализировать.
 
 Минимальный размер сокета для любой реализации - 16 байт.
 in_addr_t   - 4 байта
 in_port_t   - 2 байта
 sa_family_t - 1 или 2 байта
 
И адрес , и порт в этой структуре хранятся в том порядке байт , который принят в интернете .

Есть 4 функции , передающие сокет от процесса к ядру :


 bind
 connect
 sendto
 sendmsg
 
Есть 5 функций , передающих сокет обратно :

 accept
 recvfrom
 recvmsg
 getpeername
 getcockname
 
Во всех функциях сокет всегда передается по ссылке. Тип передаваемого указателя формируется с помощью структуры адреса сокета :

 struct sockaddr {
 	 uint8_t         sa_len; 
         sa_family_t     sa_family;      /* address family, AF_xxx       */
         char            sa_data[14];    /* 14 bytes of protocol address */
 };
  
  Пример использования :
 
 	struct sockaddr_in serv;
 	bind(fd , (struct sockaddr * ) &serv , sizeof(ser))
 
 
 

 Яковлев С: В 10-й SUSE это прописано в /include/linux/socket.h :
 struct sockaddr {
         sa_family_t     sa_family;      /* address family, AF_xxx       */
         char            sa_data[14];    /* 14 bytes of protocol address */
 };
 
Обьявление функции выглядит так :

 int bind(int , struct soxkaddr *, socklen_t);
 
Реализация функции выглядит так :

 struct sockaddr_in serv;
 int bind(sockfd , (struct soxkaddr *) &serv, sizeof(serv));
 
Структура сокета IPv6 :

 struct in6_addr
 {
 	uint8t  s6_addr[16];
 };
 
 #define SIN6_LEN
 
 struct sockaddr_in6 {
 		uint8t 			sin6_len;
 		sa_family_t 		sin6_family;
 		in_port_t		sin6_port;
 		uint32_t		sin6_flowinfo;
 		struct in6_addr 	sin6_addr;
 };
 

 Яковлев С: В 10-й SUSE это прописано в /include/linux/in6.h :
 struct in6_addr
 {
         union
         {
                 __u8            u6_addr8[16];
                 __u16           u6_addr16[8];
                 __u32           u6_addr32[4];
         } in6_u;
 #define s6_addr                 in6_u.u6_addr8
 #define s6_addr16               in6_u.u6_addr16
 #define s6_addr32               in6_u.u6_addr32
 };
 
 struct sockaddr_in6 {
         unsigned short int      sin6_family;    /* AF_INET6 */
         __u16                   sin6_port;      /* Transport layer port # */
         __u32                   sin6_flowinfo;  /* IPv6 flow information */
         struct in6_addr         sin6_addr;      /* IPv6 address */
         __u32                   sin6_scope_id;  /* scope id (new in RFC2553) */
 };
 
IPv6 относится к AF_INET6 , IPv4 - AF_INET.
Сокет IPv6 имеет фиксированную длину в 24 байта , т.е. он в полтора раза больше IPv4.

В функцию , кроме того , что сам сокет передается по ссылке , также передается длина сокета. Имеется 2 варианта способа передачи второго параметра - длины сокета :

1. Передача от процесса к ядру :


  	bind
 	connect
 	sendto
 
Здесь способ передачи 2-го параметра - по значению :

 	struct sockaddr_in serv;
 	connect(sockfd,(SA *) &serv,sizeof(serv));
 
2. Передача от ядра к процессу :

 	accept
 	recvfrom
 	getsockname
 	getpeername
 
Здесь 2-й аргумент передается по ссылке , в не по значению - это говорит о том , что размер может быть изменен ядром :

 	struct sockaddr_un cli;
 	socklen_t len;
 	len = sizeof(cli);
 	getpeername(unixfd,(SA *) &cli , &len);
 
Есть сокеты , которые имеют переменную , а не фиксированную длину.

Определение порядка байтов

2 байта в памяти можно положить 2-мя способами :
1. little-endian - первым идет младший байт
2. big-endian - первым идет старший байт
Способ упорядочивания байтов в системе - host byte order - определяется в следующей программе :

 // intro/byteorder.c
 
 #include	"unp.h"
 
 int main(int argc, char **argv)
 {
 	union {
 	  short  s;
       char   c[sizeof(short)];
     } un;
 
 	un.s = 0x0102;
 	printf("%s: ", CPU_VENDOR_OS);
 	if (sizeof(short) == 2) {
 		if (un.c[0] == 1 && un.c[1] == 2)
 			printf("big-endian\n");
 		else if (un.c[0] == 2 && un.c[1] == 1)
 			printf("little-endian\n");
 		else
 			printf("unknown\n");
 	} else
 		printf("sizeof(short) = %d\n", sizeof(short));
 
 	exit(0);
 }
 
2-байтное значение 0x0102 помещается в переменную типа short и проверяем значения 2-х байтов этой переменной - c[0] и c[1].
Пример можно взять тут

В сетевых протоколах используется обратный порядок байтов - network byte order. И задача программиста - привести порядок байтов узла в сетевой , а потом обратно. Для этого используются 2 функции , возврающие значение , записанное в сетевом порядке байтов :


 	uint16_t htons(uint16_t host16bitvalue);
 	uint32_t htonl(uint32_t host32bitvalue);
 
2 функции , возврающие значение , записанное в порядке байтов узла :

 	uint16_t ntohs(uint16_t host16bitvalue);
 	uint32_t ntohl(uint32_t host32bitvalue);
 
По определению байт - это 8 бит . Но 8 бит - это также октет .

Функции управления байтами

Существуют 2 группы функций для работы с многобайтовыми полями.

1. Первая группа функция взята из стандарта BSD.


 	void bzero(void *dest,size_t nbytes);
 	void bcopy(const void *src,void *dest,size_t nbytes);
 	int bcmp(const void *ptr1,const void *ptr2,size_t nbytes);
 
bzero - обнуляет заданное число байтов в указанной облачти памяти. bcopy - копирует заданное число байтов из источника в приемник. bcmp - сравнивает 2 байтовых последовательности.

2. Вторая группа функций взята из стандарта ANSI C.


 	void *memset(void *dest,int c , size_t len);
 	void *memcpy(void *dest,int c , size_t len);
 	int  memcmp(const void *ptr1,const void *ptr2,size_t nbytes);
 
Есть некоторые различия в работе этих функций и 1-й группы.

Функции преобразования адресов

Существуют 2 группы таких функций :

1. Функции , работающие только с IPv4 :


 	inet_aton
 	inet_ntoa
 	inet_addr
 
Они преобразуют адрес из точечно-десятичной (10.10.11.12) в 4-х байтную двоичную или наоборот. inet_addr считается устаревшей.

2. Функции , работающие и с IPv4 , и с IPv6 :


 	inet_pton
 	inet_ntop
 
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье