stringtranslate.com

Сокет домена Unix

В клиент-серверных вычислениях сокет домена Unix — это сокет Беркли , который позволяет обмениваться данными между двумя процессами , выполняющимися на одном и том же хост-компьютере Unix или Unix-подобном компьютере. [1] Это похоже на сокет домена Интернета , который позволяет обмениваться данными между двумя процессами, выполняющимися на разных хост-компьютерах.

Независимо от диапазона коммуникации (один и тот же хост или другой хост), [2] компьютерные программы Unix , которые выполняют коммуникацию сокетов , похожи. Единственное различие диапазона коммуникации — это метод преобразования имени в параметр адреса, необходимый для привязки соединения сокета. Для сокета домена Unix имя — . Для сокета домена Интернета имя — . В любом случае имя называется адресом . [ 3]/path/filenameIP address:Port number

Два процесса могут взаимодействовать друг с другом, если каждый получает сокет. Серверный процесс привязывает свой сокет к адресу , открывает канал прослушивания , а затем непрерывно выполняет цикл . Внутри цикла серверный процесс переходит в спящий режим, ожидая принятия клиентского соединения. [4] После принятия клиентского соединения сервер выполняет системный вызов read , который блокирует wait . Клиент подключается к сокету сервера через адрес сервера . Затем клиентский процесс записывает сообщение для серверного процесса для чтения. Алгоритм приложения может включать в себя несколько взаимодействий чтения/записи. После завершения алгоритма клиент выполняет [5] , а сервер выполняет . [6 ]exit()close()

Для сокета домена Unix адрес сокета является /path/filenameидентификатором. Сервер создаст /path/filenameв файловой системе семафор для работы в качестве файла блокировки . В этом файле не происходит ввода-вывода, когда клиент и сервер отправляют друг другу сообщения. [7]

История

Сокеты впервые появились в Berkeley Software Distribution 4.2 (1983). [8] Он стал стандартом POSIX в 2000 году. [8] Интерфейс прикладного программирования был перенесен практически на все реализации Unix и большинство других операционных систем. [8]

Создание сокета

И сервер, и клиент должны создать экземпляр объекта сокета , выполнив socket() системный вызов . Его использование: [9]

int сокет ( int домен , int тип , int протокол );        

Параметр domainдолжен быть одним из следующих общих диапазонов связи : [10]

  1. В пределах одного хоста с использованием константы AF_UNIX[a]
  2. Между двумя хостами по протоколу IPv4 с использованием константыAF_INET
  3. Между двумя хостами по протоколу IPv6 с использованием константыAF_INET6
  4. В пределах одного хоста или между двумя хостами через протокол передачи управления потоком с использованием константы SOCK_SEQPACKET[11]

Метка сокета домена Unix используется , когда domainзначение параметра равно AF_UNIX. Метка сокета домена Интернета используется, когда domainзначение параметра равно AF_INETили AF_INET6. [12]

Параметр typeдолжен быть одним из двух распространенных типов сокетов: поток или датаграмма. [10] Третий тип сокета доступен для экспериментального проектирования: raw.

  1. SOCK_STREAMсоздаст потоковый сокет. Потоковый сокет обеспечивает надежный, двунаправленный и ориентированный на соединение канал связи между двумя процессами. Данные передаются с использованием протокола управления передачей (TCP). [10]
  2. SOCK_DGRAMсоздаст датаграммный сокет. [b] Датаграммный сокет не гарантирует надежности и не требует соединения . В результате передача происходит быстрее. Данные переносятся с использованием протокола пользовательских датаграмм (UDP). [14]
  3. SOCK_RAWсоздаст сокет датаграммы Интернет-протокола (IP) . Сокет Raw пропускает транспортный уровень TCP/UDP и отправляет пакеты напрямую на сетевой уровень . [15]

Для сокета домена Unix данные ( сетевые пакеты ) передаются между двумя связанными процессами через транспортный уровень — либо TCP, либо UDP. [16] Для сокета домена Интернета данные передаются между двумя связанными процессами через транспортный уровень и интернет-протокол (IP) сетевого уровня — либо TCP/IP, либо UDP/IP. [16]

Параметр protocolдолжен быть установлен на ноль для потоковых и датаграммных сокетов. [2] Для необработанных сокетов protocolпараметр должен быть установлен на IPPROTO_RAW. [9]

socket() возвращаемое значение

socket_fd = сокет ( домен int , тип int , протокол int );         

Как и обычный open()системный вызов файла, socket()системный вызов возвращает дескриптор файла . [2] [c] Суффикс возвращаемого значения _fdобозначает дескриптор файла .

Привязка сервера к /path/filename

После создания нового сокета сервер привязывает сокет к адресу. Для сокета домена Unix адресом является /path/filename.

Поскольку адрес сокета может быть либо a, /path/filenameлибо an , интерфейс программирования приложенийIP_address:Port_number сокетов требует, чтобы адрес был сначала установлен в структуру. Для сокета домена Unix структура такова: [17]

struct sockaddr_un { sa_family_t sun_family ; /* AF_UNIX */ char sun_path [ 92 ]; }         

Суффикс _unозначает unix . Для интернет-доменного сокета суффикс будет либо , _inлибо _in6. sun_Префикс означает socket 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>        /* Должно быть 91 символ или меньше. Некоторые Unix-подобные немного больше. */ /* Используйте каталог /tmp только для демонстрации. */ 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 = сокет ( AF_UNIX , SOCK_STREAM , 0 ); если ( server_socket_fd == -1 ) утвердить ( 0 );                /* Удалить (возможно) предыдущий запуск. */ remove ( socket_address );    /* Построение структуры адреса привязки. */ 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 ) );             /* Если socket_address существует в файловой системе, то привязка завершится ошибкой. */ if ( return_value == -1 ) assert ( 0 );          /* Код прослушивания и принятия пропущен. */ }

Второй параметр для bind()— это указатель на struct sockaddr. Однако параметр, переданный функции, — это адрес struct sockaddr_un. struct sockaddr— это общая структура, которая не используется. Она определена в формальном объявлении параметра для . Поскольку каждый диапазон связи имеет свой собственный фактический параметр , эта общая структура была создана как заполнитель приведения. [18]bind()

Сервер ожидает соединения

После привязки к адресу сервер открывает канал прослушивания порта, выполняя . listen()Его использование: [19]

int listen ( int server_socket_fd , int backlog );      

Фрагмент для прослушивания:

если ( прослушивать ( server_socket_fd , 4096 ) == -1 ) утверждать ( 0 );           

Для сокета домена Unix , listen()скорее всего, будет успешным и вернет 0. Для сокета домена Интернета , если порт используется, listen()вернет -1. [19]

Параметр backlogустанавливает размер очереди для ожидающих подключений. [20] Сервер может быть занят, когда клиент выполняет connect()запрос. Запросы на подключение до этого предела будут успешными. Если переданное значение backlog превышает максимум по умолчанию, то используется максимальное значение. [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 );                    если ( accept_socket_fd ) > 0 ) /* клиент подключен */ }       

Серверный ввод-вывод на сокете

Когда 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 );                    если ( accept_socket_fd > 0 ) { диалог_алгоритма_сервера ( accept_socket_fd ); } }          #define BUFFER_SIZE 1024void server_algorithmic_dialog ( int accept_socket_fd ) { char input_buffer [ BUFFER_SIZE ]; char output_buffer [ BUFFER_SIZE ];             чтение ( accept_socket_fd , input_buffer , BUFFER_SIZE );     если ( strcasecmp ( input_buffer , "hola" ) == 0 ) strcpy ( output_buffer , "Hola Mundo" ); иначе если ( strcasecmp ( input_buffer , "ciao" ) == 0 ) strcpy ( output_buffer , "Ciao Mondo" ); иначе strcpy ( output_buffer , "Hello World" );                                запись ( 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 );                    если ( accept_socket_fd > 0 ) { server_algorithmic_dialog ( accept_socket_fd ); закрыть ( accept_socket_fd ); } }             

Фрагмент, иллюстрирующий конец диалога:

#define BUFFER_SIZE 1024void server_algorithmic_dialog ( int accept_socket_fd ) { буфер символов [ BUFFER_SIZE ]; int read_count ;           /* Пропустить алгоритмический диалог */ read_count = read ( accept_socket_fd , buffer , BUFFER_SIZE ); если ( read_count < 1 ) return ;              /* Пропустить алгоритмический диалог */ }

Клиент создает экземпляр и подключается к /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>        /* Должен соответствовать 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 = сокет ( AF_UNIX , SOCK_STREAM , 0 ); если ( client_socket_fd == -1 ) утвердить ( 0 );                /* Построение структуры адреса клиента. */ 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 ) );             /* Если socket_address не существует в файловой системе, */ /* или если очередь запросов на подключение сервера заполнена, */ /* то connect() завершится ошибкой. */ if ( return_value == -1 ) assert ( 0 );            /* закрыть( client_socket_fd ); <-- необязательно */ выход ( EXIT_SUCCESS ); }  

Клиентский ввод-вывод на сокете

Если connect()возвращает ноль, клиент может участвовать в алгоритмическом диалоге с сервером. Клиент может отправлять потоковые данные через write( client_socket_fd )и может получать потоковые данные через read( client_socket_fd ).

Фрагмент, иллюстрирующий клиентский ввод-вывод на потоковом сокете:

{ /* Пропустить код конструкции */ return_value = connect ( client_socket_fd , ( struct sockaddr * ) & sockaddr_un , sizeof ( struct sockaddr_un ) );               если ( возвращаемое_значение == -1 ) утвердить ( 0 );         если ( return_value == 0 ) { client_algorithmic_dialog ( client_socket_fd ); }           /* закрыть( client_socket_fd ); <-- необязательно */ /* Когда клиентский процесс завершается, */ /* если сервер пытается выполнить read(), */ /* тогда read_count будет равен 0 или -1. */ /* Это сообщение для сервера */ /* для выполнения close(). */ exit ( EXIT_SUCCESS ); }       #define BUFFER_SIZE 1024void client_algorithmic_dialog ( int client_socket_fd ) { буфер символов [ 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 );                    если ( read_count > 0 ) помещает ( буфер ); }        

Смотрите также

Ссылки

  1. ^ Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1149. ISBN 978-1-59327-220-3Сокеты — это метод IPC, позволяющий обмениваться данными между приложениями, как на одном хосте (компьютере), так и на разных хостах, соединенных сетью.
  2. ^ abc Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1150. ISBN 978-1-59327-220-3.
  3. ^ Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1150. ISBN 978-1-59327-220-3. Сервер привязывает свой сокет к известному адресу (имени), чтобы клиенты могли его найти.
  4. ^ ab Стивенс, Ричард В.; Феннер, Билл; Рудофф, Эндрю М. (2004). Сетевое программирование Unix (3-е изд.). Pearson Education. стр. 14. ISBN 81-297-0710-1. Обычно серверный процесс приостанавливается при вызове accept , ожидая прибытия клиентского соединения и его принятия.
  5. ^ ab Kerrisk, Michael (2010). Интерфейс программирования Linux . No Starch Press. стр. 1169. ISBN 978-1-59327-220-3.
  6. ^ abcd Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1159. ISBN 978-1-59327-220-3.
  7. ^ ab Kerrisk, Michael (2010). Интерфейс программирования Linux . No Starch Press. стр. 1166. ISBN 978-1-59327-220-3.
  8. ^ abc Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1149. ISBN 978-1-59327-220-3.
  9. ^ ab Kerrisk, Michael (2010). Интерфейс программирования Linux . No Starch Press. стр. 1153. ISBN 978-1-59327-220-3.
  10. ^ abc Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1151. ISBN 978-1-59327-220-3.
  11. ^ ab "Руководство программиста Linux (сокеты unix для локального межпроцессного взаимодействия)". 30 апреля 2018 г. Получено 22 февраля 2019 г.
  12. ^ Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1197. ISBN 978-1-59327-220-3.
  13. ^ Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1183. ISBN 978-1-59327-220-3.
  14. ^ Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1152. ISBN 978-1-59327-220-3.
  15. ^ Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1184. ISBN 978-1-59327-220-3.
  16. ^ ab Kerrisk, Michael (2010). Интерфейс программирования Linux . No Starch Press. стр. 1181. ISBN 978-1-59327-220-3.
  17. ^ ab Kerrisk, Michael (2010). Интерфейс программирования Linux . No Starch Press. стр. 1165. ISBN 978-1-59327-220-3.
  18. ^ Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1154. ISBN 978-1-59327-220-3.
  19. ^ abc "Страница руководства Linux для listen()".
  20. ^ Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1157. ISBN 978-1-59327-220-3.
  21. ^ "Страница руководства Linux для accept()".
  22. ^ Керриск, Майкл (2010). Интерфейс программирования Linux . No Starch Press. стр. 1160. ISBN 978-1-59327-220-3.

Примечания

  1. ^ В качестве альтернативы можно использовать PF_UNIXили . [11] AF означает «Address Family», а PF означает «Protocol Family».AF_LOCAL
  2. ^ Сокет дейтаграммы не следует путать с пакетом дейтаграммы, используемым на сетевом уровне . [13]
  3. ^ В UNIX все является файлом .