Сокеты
На сегодняшний день практически все распределённые системы работают с использованием сокетов.
Создание сокета
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);domain- коммуникационный домен:AF_UNIXAF_INET
type- тип сокета:SOCK_STREAM- виртуальный канал (логическое соединение между взаимодействующими сокетами и соблюдение порядка отправки и приёма сообщений от начала до конца работы канала)SOCK_DGRAM- датаграммы (нет предварительной установки соединения. Не гарантируется порядок отправки и приёма сообщений. Не гарантируется доставка сообщений)
protocol- протокол:0- автоматический выбор протоколаIPPROTO_TCP- протокол TCP(AF_NET)IPPROTO_UDP- протокол UDP(AF_NET)
Возвращает файловый дескриптор для нового сокета. -1 и errno в случае ошибки.
Тип коммуникационного домена определяет способ адресации
Для датаграмм также доступен TCP.
Связывание
Окей. Сокет создали. Как его теперь найти?
Когда сокет создан socket(), он существует в пространстве имён, но не имеет связанного адреса. bind() привызяывает адрес из addr к сокету.
#include <sys/tupes.h>
#include <sys/socket.h>
#include <sys/un.h>
struct sockaddr_un {
short sun_family; // AF_UNIX
char sun_path[108];
};
#include <netinet/in.h>
struct sockaddr_in {
short sin_family; // == AF_INET
u_short sin_port; // port number
struct in_addr sin_addr; // host IP address
char sin_zero[8]; // not used
}int bind(int sockfd, struct sockaddr *addr, int addrlen);sockfd- дескриптор сокета.addr- указатель на структуру, содержащую адрес сокета.addrlen- размер структуры в байтах.
Возвращает 0 или -1, в случае ошибки
Часть портов зарезервирована. Частью можно пользоваться.
Есть специальные IP для связывания программ внутри одной машины: 127.0.0.1 и localhost.
Прослушивание сокета
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);sockfd- дескриптор сокета.backlog- максимальный размер очереди запросов на соединение.
Возвращает 0 или -1, в случае ошибки. Код ошибки в errno.
Концепции Mark
Предварительное установление соединения
img
Клиент-сервер на сокетах.
Сервер
socket()- На сервере создаём сокетbind()- Сокету даётся имя черезlisten()- Сервер вызывает метод (man читаем)accept()- обработка запроса (блокировка, если запросов нет). Если подключение принято, accept() создаёт под клиента ещё один сокет.send()<->reсv()- пользователь отправляет запросы, сервер отвечает.shutdown()close()
Таблица файловых дескрипторов ограничена (10 по умолчанию). Пользователей много. Таблица очень быстро закончится.
Поэтому послеaccept()следует делатьfork(). Выделять под пользователя новый процесс.
Клиент
socket()-- (
bind()- не обязательно) connect()-
Читаем в man про запрос, превосходящий размер очереди, определённой в listen
Сокеты без предварительного соединения
Датаграммные сокеты (для отправки одного сообщения)
1
socket()bind()sedto()<->recvfrom()- (
shutdown) - …
2
socket()- …
Запрос на соединение Mark
#include <sys/types.h>
int Подтверждение соединения Mark
#include <
int accept(int sockfd, struct sockaddr *addr, int *addrlen)Приём и передача данных Mark
#include <
Необходимые заголовочные файлы и прототип
#include <sys/types.h>
#include <sys/socket.h>Завершение работы с сокетом
#include <sys/types.h>
#include <sys/types.h>
int shutdown(int sockfd, int mode) // жёсткое закрытие
int close(int fd) // мягкое закрытиеsockfd- дескриптор сокета.mode- режим закрытия соединения.0- сокет закрывается для чтения.1- сокет закрывается для записи.2- сокет закрывается и для чтения, и для записи.
Возвращают 0 в случае успеха. -1 и errno в случае ошибки.
shutdown() может закрыть сокет полностью или частично.
close() закрывает только текущий дескриптор.
Проблема NUXI - Big-endian и little-endian при вызове bind() Mark
Разные устройства в сети могут использовать различные записи двоичных чисел. Также машины могут иметь разную разрядность.
Для решения проблемы есть специальные системные вызовы.
Пример: сокеты с установлением соединения в localhost.
Клиент
#include <
#include <
#include <
#include <
#include <
#include <
#define PORTNUM 50500
#define BUFLEN 80
int main(int argc, char **argv) {
struct
}Сервер
Запустить на своей машине. Поиграться.
Пример: сокеты без предварительного установления соединения на localhost.
AF_INET - Процесс 1
AF_INET - Процесс 2