Доменный сокет Unix
В клиент-серверных вычислениях сокет домена Unix — это сокет Беркли , который позволяет обмениваться данными между двумя процессами , выполняющимися на одном и том же Unix- или Unix-подобном хост-компьютере. [ 1 ] Это похоже на сокет домена Интернета , который позволяет обмениваться данными между двумя процессами, выполняющимися на разных хост-компьютерах.
Независимо от диапазона связи (тот же хост или другой хост), [ 2 ] Unix Компьютерные программы , выполняющие через сокеты, связь аналогичны. Единственное различие в способах связи — это метод преобразования имени в параметр адреса, необходимый для привязки соединения сокета. Для сокета домена Unix именем является /path/filename
. Для сокета домена Интернета именем является IP address:Port number
. В любом случае имя называется адресом . [ 3 ]
Два процесса могут взаимодействовать друг с другом, если каждый из них получает сокет. Серверный процесс привязывает свой сокет к адресу , открывает канал прослушивания , а затем непрерывно зацикливается . Внутри цикла серверный процесс приостанавливается в ожидании принятия клиентского соединения. [ 4 ] Приняв клиентское соединение , сервер затем выполняет чтения системный вызов , который блокирует ожидание . Клиент подключается сервера к сокету сервера через адрес . клиентский процесс записывает сообщение Затем для чтения серверным процессом. приложения Алгоритм может включать в себя несколько операций чтения/записи. По завершении алгоритма клиент выполняет exit()
[ 5 ] и сервер выполняет close()
. [ 6 ]
Для сокета домена Unix адрес сокета представляет собой /path/filename
идентификатор. Сервер создаст /path/filename
в файловой системе , чтобы действовать как файла блокировки семафор . В этом файле не происходит ввода-вывода, когда клиент и сервер отправляют сообщения друг другу. [ 7 ]
История
[ редактировать ]Сокеты впервые появились в Berkeley Software Distribution 4.2 (1983). [ 8 ] Он стал стандартом POSIX в 2000 году. [ 8 ] Интерфейс прикладного программирования был перенесен практически на каждую реализацию Unix и большинство других операционных систем. [ 8 ]
Создание экземпляра сокета
[ редактировать ]И сервер, и клиент должны создать экземпляр объекта сокета , выполнив команду socket()
системный вызов . Его использование: [ 9 ]
int socket( int domain, int type, int protocol );
The domain
Параметр должен быть одним из следующих общих диапазонов связи : [ 10 ]
- В пределах одного хоста, используя константу
AF_UNIX
[ а ] - Между двумя хостами по протоколу IPv4 с использованием константы
AF_INET
- Между двумя хостами по протоколу IPv6 с использованием константы
AF_INET6
- В пределах одного хоста или между двумя хостами через протокол передачи управления потоком с использованием константы
SOCK_SEQPACKET
[ 11 ]
Метка сокета домена Unix используется, когда domain
значение параметра AF_UNIX
. Метка сокета домена Интернета используется, когда domain
значение параметра либо AF_INET
или AF_INET6
. [ 12 ]
The type
Параметр должен быть одним из двух распространенных типов сокетов: поток или датаграмма. [ 10 ] Для экспериментального проектирования доступен третий тип сокета: необработанный.
SOCK_STREAM
создаст потоковый сокет. Потоковый сокет обеспечивает надежный, двунаправленный и ориентированный на соединение канал связи между двумя процессами. Данные передаются с использованием протокола управления передачей (TCP). [ 10 ]SOCK_DGRAM
создаст дейтаграммный сокет. [ б ] Сокет дейтаграммы не гарантирует надежность и не поддерживает соединение . В результате передача происходит быстрее. Данные передаются с использованием протокола пользовательских дейтаграмм (UDP). [ 14 ]SOCK_RAW
создаст Интернет-протокола (IP) сокет датаграммы . Сокет Raw пропускает транспортный уровень TCP/UDP и отправляет пакеты непосредственно на сетевой уровень . [ 15 ]
Для сокета домена Unix данные ( сетевые пакеты ) передаются между двумя подключенными процессами через транспортный уровень — TCP или UDP. [ 16 ] Для сокета интернет-домена данные передаются между двумя подключенными процессами через транспортный уровень и интернет-протокол (IP) сетевого уровня — TCP/IP или UDP/IP. [ 16 ]
The protocol
Параметр должен быть установлен в ноль для потоковых и дейтаграммных сокетов. [ 2 ] Для необработанных сокетов protocol
параметр должен быть установлен на IPPROTO_RAW. [ 9 ]
возвращаемое значение сокета()
[ редактировать ]socket_fd = socket( int domain, int type, int protocol );
Как обычный файл open()
системный вызов, socket()
системный вызов возвращает дескриптор файла . [ 2 ] [ с ] Суффикс возвращаемого значения _fd
означает файловый дескриптор .
Привязка сервера к /path/имя файла
[ редактировать ]После создания экземпляра нового сокета сервер привязывает сокет к адресу. Для сокета домена Unix адресом является /path/filename
.
Поскольку адрес сокета может быть либо /path/filename
или IP_address:Port_number
сокета , программный интерфейс приложения требует, чтобы адрес сначала был установлен в структуру. Для доменного сокета Unix структура следующая: [ 17 ]
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[ 92 ];
}
The _un
суффикс означает unix . Для сокета домена Интернета суффикс будет либо _in
или _in6
. sun_
префикс означает сокет unix . [ 17 ]
Компьютерная программа для создания и привязки потокового сокета домена Unix : [ 7 ]
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
/* Should be 91 characters or less. Some Unix-like are slightly more. */
/* Use /tmp directory for demonstration only. */
char *socket_address = "/tmp/mysocket.sock";
void main( void )
{
int server_socket_fd;
struct sockaddr_un sockaddr_un = {0};
int return_value;
server_socket_fd = socket( AF_UNIX, SOCK_STREAM, 0 );
if ( server_socket_fd == -1 ) assert( 0 );
/* Remove (maybe) a prior run. */
remove( socket_address );
/* Construct the bind address structure. */
sockaddr_un.sun_family = AF_UNIX;
strcpy( sockaddr_un.sun_path, socket_address );
return_value =
bind(
server_socket_fd,
(struct sockaddr *) &sockaddr_un,
sizeof( struct sockaddr_un ) );
/* If socket_address exists on the filesystem, then bind will fail. */
if ( return_value == -1 ) assert( 0 );
/* Listen and accept code omitted. */
}
Второй параметр для bind()
является указателем на struct sockaddr
. Однако параметр, передаваемый в функцию, является адресом struct sockaddr_un
. struct sockaddr
это общая структура, которая не используется. Он определен в формального параметра объявлении для bind()
. Поскольку каждый диапазон связи имеет свой собственный фактический параметр , эта общая структура была создана как заполнитель приведения. [ 18 ]
Сервер прослушивает соединение
[ редактировать ]После привязки к адресу сервер открывает канал прослушивания порта , выполняя listen()
. Его использование: [ 19 ]
int listen( int server_socket_fd, int backlog );
Фрагмент для прослушивания:
if ( listen( server_socket_fd, 4096 ) == -1 ) assert( 0 );
Для сокета домена Unix : listen()
скорее всего добьюсь успеха и вернусь 0
. Для сокета домена Интернета , если порт используется, listen()
возвращает -1
. [ 19 ]
The backlog
Параметр задает размер очереди для ожидающих соединений. [ 20 ] Сервер может быть занят, когда клиент выполняет connect()
запрос. Запросы на подключение до этого предела будут успешными. Если переданное значение невыполненной работы превышает максимум по умолчанию, то используется максимальное значение. [ 19 ]
Сервер принимает соединение
[ редактировать ]После открытия канала прослушивания сервер входит в бесконечный цикл . Внутри цикла находится системный вызов accept()
, который усыпляет себя. [ 4 ] accept()
системный вызов вернет дескриптор файла при выполнении клиентского процесса connect()
. [ 21 ]
Фрагмент для принятия соединения:
int accept_socket_fd;
while ( 1 )
{
accept_socket_fd = accept( server_socket_fd, NULL, NULL );
if ( accept_socket_fd == -1 ) assert( 0 );
if ( accept_socket_fd ) > 0 ) /* client is connected */
}
Серверный ввод-вывод на сокете
[ редактировать ]Когда accept()
возвращает положительное целое число, сервер вступает в алгоритмический диалог с клиентом.
Ввод/вывод потокового сокета может выполнять вызовы обычной файловой системы read()
и write()
. [ 6 ] Однако больший контроль доступен, если потоковый сокет выполняет системные вызовы, специфичные для сокета: send()
и recv()
. Альтернативно, ввод/вывод сокета дейтаграммы должен выполнять системные вызовы, специфичные для сокета: sendto()
и recvfrom()
. [ 22 ]
Для базового сокета потока сервер получает данные с read( accept_socket_fd )
и отправляет данные с помощью write( accept_socket_fd )
.
Фрагмент, иллюстрирующий ввод-вывод в базовом сокете потока:
int accept_socket_fd;
while ( 1 )
{
accept_socket_fd = accept( server_socket_fd, NULL, NULL );
if ( accept_socket_fd == -1 ) assert( 0 );
if ( accept_socket_fd > 0 )
{
server_algorithmic_dialog( accept_socket_fd );
}
}
#define BUFFER_SIZE 1024
void server_algorithmic_dialog(
int accept_socket_fd )
{
char input_buffer[ BUFFER_SIZE ];
char output_buffer[ BUFFER_SIZE ];
read( accept_socket_fd, input_buffer, BUFFER_SIZE );
if ( strcasecmp( input_buffer, "hola" ) == 0 )
strcpy( output_buffer, "Hola Mundo" );
else
if ( strcasecmp( input_buffer, "ciao" ) == 0 )
strcpy( output_buffer, "Ciao Mondo" );
else
strcpy( output_buffer, "Hello World" );
write( accept_socket_fd, output_buffer, strlen( output_buffer ) + 1 );
}
Сервер закрывает соединение
[ редактировать ]Алгоритмический диалог заканчивается, когда алгоритм завершает работу или read( accept_socket_fd )
возвращает < 1
. [ 6 ] Чтобы закрыть соединение, выполните команду close()
системный вызов: [ 6 ]
Фрагмент для закрытия соединения:
int accept_socket_fd;
while ( 1 )
{
accept_socket_fd = accept( server_socket_fd, NULL, NULL );
if ( accept_socket_fd == -1 ) assert( 0 );
if ( accept_socket_fd > 0 )
{
server_algorithmic_dialog( accept_socket_fd );
close( accept_socket_fd );
}
}
Фрагмент, иллюстрирующий конец диалога:
#define BUFFER_SIZE 1024
void server_algorithmic_dialog(
int accept_socket_fd )
{
char buffer[ BUFFER_SIZE ];
int read_count;
/* Omit algorithmic dialog */
read_count = read( accept_socket_fd, buffer, BUFFER_SIZE );
if ( read_count < 1 ) return;
/* Omit algorithmic dialog */
}
Клиент создает экземпляр и подключается к /path/filename
[ редактировать ]Компьютерная программа для клиента для создания экземпляра и подключения сокета: [ 5 ]
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
/* Must match the server's socket_address. */
char *socket_address = "/tmp/mysocket.sock";
void main( void )
{
int client_socket_fd;
struct sockaddr_un sockaddr_un = {0};
int return_value;
client_socket_fd = socket( AF_UNIX, SOCK_STREAM, 0 );
if ( client_socket_fd == -1 ) assert( 0 );
/* Construct the client address structure. */
sockaddr_un.sun_family = AF_UNIX;
strcpy( sockaddr_un.sun_path, socket_address );
return_value =
connect(
client_socket_fd,
(struct sockaddr *) &sockaddr_un,
sizeof( struct sockaddr_un ) );
/* If socket_address doesn't exist on the filesystem, */
/* or if the server's connection-request queue is full, */
/* then connect() will fail. */
if ( return_value == -1 ) assert( 0 );
/* close( client_socket_fd ); <-- optional */
exit( EXIT_SUCCESS );
}
Клиентский ввод-вывод на сокете
[ редактировать ]Если connect()
возвращает ноль, клиент может вступить в алгоритмический диалог с сервером. Клиент может отправлять потоковые данные через write( client_socket_fd )
и может получать потоковые данные через read( client_socket_fd )
.
Фрагмент, иллюстрирующий клиентский ввод-вывод в сокете потока:
{
/* Omit construction code */
return_value =
connect(
client_socket_fd,
(struct sockaddr *) &sockaddr_un,
sizeof( struct sockaddr_un ) );
if ( return_value == -1 ) assert( 0 );
if ( return_value == 0 )
{
client_algorithmic_dialog( client_socket_fd );
}
/* close( client_socket_fd ); <-- optional */
/* When the client process terminates, */
/* if the server attempts to read(), */
/* then read_count will be either 0 or -1. */
/* This is a message for the server */
/* to execute close(). */
exit( EXIT_SUCCESS );
}
#define BUFFER_SIZE 1024
void client_algorithmic_dialog(
int client_socket_fd )
{
char buffer[ BUFFER_SIZE ];
int read_count;
strcpy( buffer, "hola" );
write( client_socket_fd, buffer, strlen( buffer ) + 1 );
read_count = read( client_socket_fd, buffer, BUFFER_SIZE );
if ( read_count > 0 ) puts( buffer );
}
См. также
[ редактировать ]- Конвейер (Unix) — механизм межпроцессного взаимодействия с использованием передачи сообщений.
- Netlink — интерфейс ядра Linux для межпроцессного взаимодействия между процессами.
Ссылки
[ редактировать ]- ^ Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1149. ИСБН 978-1-59327-220-3 .
Сокеты — это метод IPC, который позволяет обмениваться данными между приложениями как на одном хосте (компьютере), так и на разных хостах, соединенных сетью.
- ^ Перейти обратно: а б с Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1150. ИСБН 978-1-59327-220-3 .
- ^ Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1150. ИСБН 978-1-59327-220-3 .
Сервер привязывает свой сокет к известному адресу (имени), чтобы клиенты могли его найти.
- ^ Перейти обратно: а б Стивенс, Ричард В.; Феннер, Билл; Рудофф, Эндрю М. (2004). Сетевое программирование Unix (3-е изд.). Пирсон Образование. п. 14. ISBN 81-297-0710-1 .
Обычно серверный процесс приостанавливается при вызове Accept , ожидая прибытия и принятия клиентского соединения.
- ^ Перейти обратно: а б Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1169. ИСБН 978-1-59327-220-3 .
- ^ Перейти обратно: а б с д Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1159. ИСБН 978-1-59327-220-3 .
- ^ Перейти обратно: а б Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1166. ИСБН 978-1-59327-220-3 .
- ^ Перейти обратно: а б с Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1149. ИСБН 978-1-59327-220-3 .
- ^ Перейти обратно: а б Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1153. ИСБН 978-1-59327-220-3 .
- ^ Перейти обратно: а б с Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1151. ИСБН 978-1-59327-220-3 .
- ^ Перейти обратно: а б «Руководство программиста Linux (unix — сокеты для локального межпроцессного взаимодействия)» . 30 апреля 2018 года . Проверено 22 февраля 2019 г.
- ^ Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1197. ИСБН 978-1-59327-220-3 .
- ^ Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1183. ИСБН 978-1-59327-220-3 .
- ^ Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1152. ИСБН 978-1-59327-220-3 .
- ^ Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1184. ИСБН 978-1-59327-220-3 .
- ^ Перейти обратно: а б Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1181. ИСБН 978-1-59327-220-3 .
- ^ Перейти обратно: а б Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1165. ИСБН 978-1-59327-220-3 .
- ^ Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1154. ИСБН 978-1-59327-220-3 .
- ^ Перейти обратно: а б с «Страница руководства Linux для Listen()» .
- ^ Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1157. ИСБН 978-1-59327-220-3 .
- ^ «Страница руководства Linux для Accept()» .
- ^ Керриск, Майкл (2010). Программный интерфейс Linux . Нет крахмального пресса. п. 1160. ИСБН 978-1-59327-220-3 .
Примечания
[ редактировать ]- ^ Альтернативно,
PF_UNIX
илиAF_LOCAL
можно использовать. [ 11 ] AF означает «Семейство адресов», а PF означает «Семейство протоколов». - ^ дейтаграммы Сокет не следует путать с дейтаграмм, пакетом используемым на сетевом уровне . [ 13 ]
- ^ В UNIX все является файлом .