Билет 08 - honeycarbs/bmstu-os-6sem GitHub Wiki

Средства взаимодействия процессов — сокеты Беркли. Создание сокета — семейство, тип, протокол. Системный вызов sys_socket() и struct socket. Состояния сокета. Адресация сокетов и ее особенности для разных типов сокетов. Модель клиент-сервер. Сетевые сокеты — сетевой стек, аппаратный и сетевой порядок байтов. Примеры реализации взаимодействия процессов по модели клиент-сервер с использованием сокетов и мультиплексированием (лаб. раб.).

Сокеты Беркли

Сокеты - универсальное средство взаимодействия параллельных процессов. Универсальность заключается в том, что сокеты используются как и на локальной машине, так и в распределенной системе (сети), в отличие от, например, разделяемой памяти, которая применима только на отдельно стоящей машине. Сокет - абстракция конечной точки взаимодействия, потому что для разных систем сокет поддерживается в системе разными средствами. Система предоставляет пользователю соответствующее API.

Различают 3 типа сокетов:

  • Парные - альтернатива pipe, но в отличие от них обеспечивают дуплексную связь;
  • Сокеты домена UNIX - предназначены для взаимодействия параллельных процессов на локальной машине по модели клиент-сервер;
  • Сетевые (AF_INET) сокеты - предназначены для взаимодействия параллельных процессов в распределенной сети по модели клиент-сервер.

sock

PF_NETLINK - группа сокетов, созданных для обмена информацией между частями ядра, еще один интерфейс ядра, которая позволяет получить информацию из ядра в пользовательское пространство.

Создание сокета — семейство, тип, протокол.

Протоколы для взаимодействия с использованием сокетов выбираются на основе трех параметров: *

Системный вызов sys_socket() и struct socket

Функция socket в результате приведет к вызову sys_socket. Данная функция инициализирует структуру socket. Значение retval и есть тот самый дескриптор, который возвращает функция socket(). В Linux имеется один вызов и он работает как switch.

asmlinkage longsys_socketcall (int call , unsigned long * args )
{
unsigned long a [6];
unsigned long a0, a1;

Функция sock_create() инициализирует поля структуры socket.

struct socket {
	socket_state		state;

	kmemcheck_bitfield_begin(type);
	short			type;
	kmemcheck_bitfield_end(type);

	unsigned long		flags;

	struct socket_wq __rcu	*wq;

	struct file		*file;//указатель на дескриптор открытого файла
	struct sock		*sk; // коммент внизу
	const struct proto_ops	*ops;
};

Состояния сокета

У сокета различают 5 состояний, 4 из которых - стадии соединения:

  • SS_FREE - свободный сокет, с которым можно соединяться;
  • SS_UNCONNECTED - несоединенный сокет;
  • SS_CONNECTING - сокет находится в состоянии соединения;
  • SS_CONNECTED - соединенный сокет;
  • SS_DISCONNECTING - сокет разъединяется в данный момент.

Адресация сокетов и ее особенности для разных типов сокетов.

Каждый сокетный домен имеет свой формат сокетных адресов, выраженный в отдельной адресной структуре. Каждая из этих структур начинается с целочисленного поля «семейства» (с типом sa_family_t), в котором указывается тип адресной структуры. Это позволяет различным системным вызовам (например, connect(2), bind(2), accept(2),getsockname(2), getpeername(2)), которые являются общими для всех сокетов, определить домен конкретного сокетного адреса.

Для передачи сокетного адреса любого типа через программный интерфейс сокетов служит тип struct sockaddr.

typedef unsigned short sa_family_t	 
struct sockaddr {
	sa_family_t	sa_family;	/* address family, AF_xxx	*/
	char		sa_data[14];	/* 14 bytes of protocol address	*/
};

Функция socket() создает cокет, не связанный ни с локальным адресом, ни с номером порта. Прежде чем передавать данные через сокет, его необходимо связать с адресом в выбранном домене. Иногда связывание осуществляется неявно (внутри функций connect и accept), но выполнять его необходимо во всех случаях. Вид адреса зависит от выбранного домена. В Unix-домене это текстовая строка - имя файла, через который происходит обмен данными. В Internet-домене адрес задаётся комбинацией IP-адреса и 16-битного номера порта. IP-адрес определяет хост в сети, а порт - конкретный сокет на этом хосте.

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

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

В качестве первого параметра передаётся дескриптор сокета, который привязывается к заданному адресу.

Для сетевого взаимодействия определена другая структура sockaddr_in:

struct sockaddr_in
{
    short int sin_family; // Семейство адресов
    unsigned short int sin_port; // Номер порта
    struct in_addr sin_addr; // IP-адрес
    unsigned char sin_zero[8]; // Дополнение до размера структуры sockaddr
};

Модель клиент-сервер

В клиент-серверной модели существует роли распределены. Сервер предоставляет ресурсы и службы одному или нескольким клиентам, которые обращаются к серверу за обслуживанием. Большинство серверов могут устанавливать соединение "один ко многим" с клиентами. Таким образом один сервер способен предоставлять ресурсы нескольким клиентам одновременно. В момент, когда клиент запрашивает соединение с сервером, сервер может либо принять, либо отклонить запрос на соединение. Если соединение устанавливается, то оно поддерживается по определённому протоколу.

client-server

Сетевой стек

socket() - создает файловый жескриптор сокета bind() - присвоение адреса сокету listen() - режим пассивного прослушивания connect() - создает активное соединение клиента с сервером accept() - принятие соединений к серверу при условии что ранее был получен запрос

Аппаратный и сетевой порядок байтов

При присвоении значений номеру порта и адресу следует учитывать, что порядок следования байтов на разных архитектурах различен. При передаче данных по сети общепринятым является представление чисел в формате big-endian(сетевой), в котором самый старший байт целого числа имеет наименьший адрес, а самом младшем байте находится наибольший значащий байт адреса. Компьютеры, построенные на архитектуре Intel x86, используют схему представления целых чисел little-endian (аппаратный), в которой наименьший адрес имеет самый младший байт, а наибольший адрес имеет самый старший байт. Для преобразования числа из той схемы, которая используется на компьютере к той, которая используется в сети, и наоборот, применяются функции:

uint32_t htonl(uint32_t hostlong);//host to network long
uint16_t htons(uint16_t hostshort);// host to network short
uint32_t ntohl(uint32_t netlong);//network to host long
uint16_t ntohs(uint16_t netshort); //network to host short

Сокеты из лабы