Учебник по сокетам

Большинство межпроцессных взаимодействий использует клиент-серверная модель. Эти термины относятся к двум процессам, которые будут взаимодействовать друг с другом. Один из двух процессов, т. клиент, подключается к другому процессу, сервер, как правило, для запроса информации. Хорошая аналогия — это человек, который звонит другому человеку.

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

Системные вызовы для установления соединения несколько отличаются для клиента и сервера, но оба включают базовую конструкцию гнездо. Сокет — это один из концов канала межпроцессного взаимодействия. Каждый из этих двух процессов устанавливает свой собственный сокет.

  1. Создайте сокет с помощью системного вызова socket ()
  2. Подключите сокет к адресу сервера с помощью системного вызова connect ()
  3. Отправлять и получать данные. Есть несколько способов сделать это, но самый простой – использовать системные вызовы read () и write ().
  1. Создайте сокет с помощью системного вызова socket ()
  2. Привяжите сокет к адресу с помощью системного вызова bind (). Для серверного сокета в Интернете адрес состоит из номера порта на хост-машине.
  3. Прослушивание соединений с помощью системного вызова listen ()
  4. Подтвердите соединение с помощью системного вызова accept (). Этот вызов обычно блокируется до тех пор, пока клиент не соединится с сервером.
  5. Отправлять и получать данные

Типы розеток

При создании сокета программа должна указать адресный домен и тип сокета. Два процесса могут взаимодействовать друг с другом, только если их сокеты одного типа и в одном домене. Существует два широко используемых адресных домена: домен unix, в котором взаимодействуют два процесса, использующие общую файловую систему, и Интернет-домен, в котором взаимодействуют два процесса, запущенные на любых двух хостах в Интернете. Каждый из них имеет свой собственный формат адреса.

Адрес сокета в домене Unix – это символьная строка, которая по сути является записью в файловой системе.

Читайте также:
Как долго затвердевает раствор? Одеяло

Адрес сокета в Интернет-домене состоит из Интернет-адреса хост-компьютера (каждый компьютер в Интернете имеет уникальный 32-битный адрес, часто называемый его IP-адресом). Кроме того, каждому сокету нужен номер порта на этом хосте. Номера портов представляют собой 16-битные целые числа без знака. Меньшие номера зарезервированы в Unix для стандартных услуг. Например, номер порта для FTP-сервера — 21. Важно, чтобы стандартные службы были на одном и том же порту на всех компьютерах, чтобы клиенты знали свои адреса. Однако обычно доступны номера портов выше 2000.

Есть два широко используемых типа сокетов, потоковые сокетыи дейтаграммы. Потоковые сокеты обрабатывают обмен данными как непрерывный поток символов, в то время как сокеты дейтаграмм должны считывать все сообщения сразу. Каждый использует свой собственный протокол связи. Потоковые сокеты используют TCP (протокол управления передачей), который является надежным, ориентированным на поток протоколом, а сокеты дейтаграмм используют UDP (протокол дейтаграмм Unix), который ненадежен и ориентирован на сообщения.

В примерах в этом руководстве будут использоваться сокеты в домене Интернета с использованием протокола TCP.

Образец кода

Вам предоставляется код C для очень простого клиента и сервера. Они взаимодействуют с помощью потоковых сокетов в домене Интернета. Код подробно описан ниже. Однако прежде чем читать описания и смотреть код, следует скомпилировать и запустить две программы, чтобы посмотреть, что они делают.

Загрузите их в файлы с именами server.c и client.c и скомпилируйте их отдельно в два исполняемых файла с именами server и client. Они требуют специальных флагов компиляции, как указано в соответствующих программах.

В идеале вы должны запускать клиент и сервер на разных хостах в Интернете. Сначала запустите сервер. Предположим, что сервер работает на машине под названием cheerios. Когда вы запускаете сервер, вам нужно передать номер порта в качестве аргумента. Вы можете выбрать любой номер от 2000 до 65535. Если этот порт уже используется на этой машине, сервер сообщит вам об этом и завершит работу. В этом случае просто выберите другой порт и повторите попытку. Если порт доступен, сервер будет блокироваться до тех пор, пока не получит соединение от клиента. Не пугайтесь, если сервер ничего не делает; он не должен ничего делать, пока не будет установлено соединение. Вот типичная командная строка:

Читайте также:
14 идей освещения детской комнаты на 2022 год

Чтобы запустить клиент, вам нужно передать два аргумента: имя хоста, на котором работает сервер, и номер порта, на котором сервер прослушивает соединения. Вот командная строка для подключения к описанному выше серверу: Клиент предложит вам ввести сообщение. Если все работает правильно, сервер отобразит ваше сообщение на stdout, отправит клиенту подтверждающее сообщение и завершит работу. Клиент распечатает подтверждающее сообщение с сервера, а затем завершит работу.

Вы можете имитировать это на одной машине, запустив сервер в одном окне, а клиент — в другом. В этом случае вы можете использовать ключевое слово localhost в качестве первого аргумента для клиента.

Код сервера

В коде сервера используется ряд уродливых программных конструкций, поэтому мы рассмотрим его построчно.

Этот заголовочный файл содержит объявления, используемые в большинстве операций ввода и вывода, и обычно включается во все программы на C.

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

Заголовочный файл socket.h включает ряд определений структур, необходимых для сокетов.

Файл заголовка netinet/in.h содержит константы и структуры, необходимые для адресов интернет-доменов. Эта функция вызывается при сбое системного вызова. Он выводит сообщение об ошибке на stderr, а затем прерывает работу программы. Щелкните здесь, чтобы увидеть справочную страницу для perror(). sockfd и newsockfd являются файловыми дескрипторами, т. е. индексами массива в таблице файловых дескрипторов. Эти две переменные хранят значения, возвращаемые системным вызовом socket и системным вызовом accept.

portno хранит номер порта, на котором сервер принимает соединения.

clilen хранит размер адреса клиента. Это необходимо для системного вызова accept.

n — возвращаемое значение для вызовов read() и write(); т.е. содержит количество прочитанных или записанных символов. Сервер считывает символы из соединения сокета в этот буфер. sockaddr_in — это структура, содержащая интернет-адрес. Эта структура определена в . Вот определение: структура in_addr, определенная в том же заголовочном файле, содержит только одно поле, unsigned long, называемое s_addr. Переменная serv_addr будет содержать адрес сервера, а cli_addr — адрес клиента, который подключается к серверу. Пользователю необходимо передать в качестве аргумента номер порта, на котором сервер будет принимать соединения. Этот код отображает сообщение об ошибке, если пользователь не может этого сделать. Системный вызов socket() создает новый сокет. Он принимает три аргумента. Первый — адресный домен сокета. Напомним, что существует два возможных адресных домена: домен unix для двух процессов, которые совместно используют общую файловую систему, и домен Интернета для любых двух хостов в Интернете. Константа символа AF_UNIX используется для первого, а AF_INET для второго (на самом деле есть много других опций, которые можно использовать здесь для специальных целей).

Читайте также:
Венок из виниловых пластинок.

Второй аргумент — это тип сокета. Напомним, что здесь есть два варианта: потоковый сокет, в котором символы считываются непрерывным потоком, как если бы они были из файла или конвейера, и сокет дейтаграмм, в котором сообщения считываются порциями. Две символические константы — это SOCK_STREAM и SOCK_DGRAM. Третий аргумент — протокол. Если этот аргумент равен нулю (а он всегда должен быть равен нулю, за исключением необычных обстоятельств), операционная система выберет наиболее подходящий протокол. Он выберет TCP для потоковых сокетов и UDP для сокетов дейтаграмм.

Системный вызов socket возвращает запись в таблицу файловых дескрипторов (т. е. небольшое целое число). Это значение используется для всех последующих ссылок на этот сокет. Если вызов сокета терпит неудачу, он возвращает -1. В этом случае программа выводит сообщение об ошибке и завершает работу. Однако этот системный вызов вряд ли завершится ошибкой.

Это упрощенное описание вызова сокета; существует множество других вариантов доменов и типов, но эти являются наиболее распространенными. Нажмите здесь, чтобы увидеть справочную страницу сокета. Функция bzero() обнуляет все значения в буфере. Он принимает два аргумента, первый — указатель на буфер, а второй — размер буфера. Таким образом, эта строка инициализирует serv_addr нулями. Номер порта, на котором сервер будет прослушивать соединения, передается в качестве аргумента, и этот оператор использует функцию atoi() для преобразования его из строки цифр в целое число. Переменная serv_addr представляет собой структуру типа struct sockaddr_in. Эта структура имеет четыре поля. Первое короткое поле sin_family содержит код семейства адресов. Всегда должна быть установлена ​​символическая константа AF_INET. Второе поле serv_addr — это unsigned short sin_port, который содержит номер порта. Однако вместо простого копирования номера порта в это поле необходимо преобразовать его в сетевой порядок байтов с помощью функции htons(), которая преобразует номер порта в порядке байтов хоста в номер порта в сетевом порядке байтов. Третье поле sockaddr_in представляет собой структуру типа struct in_addr, которая содержит только одно поле unsigned long s_addr. Это поле содержит IP-адрес хоста. Для кода сервера это всегда будет IP-адрес машины, на которой работает сервер, и существует символическая константа INADDR_ANY, которая получает этот адрес. Системный вызов bind() привязывает сокет к адресу, в данном случае к адресу текущего хоста и номеру порта, на котором будет работать сервер. Он принимает три аргумента: дескриптор файла сокета, адрес, к которому привязан, и размер адреса, к которому он привязан. Второй аргумент — это указатель на структуру типа sockaddr, но передается структура типа sockaddr_in, поэтому она должна быть приведена к правильному типу. Это может не сработать по ряду причин, наиболее очевидной из которых является то, что этот сокет уже используется на этой машине. Щелкните здесь, чтобы увидеть справочную страницу для bind(). Системный вызов listen позволяет процессу прослушивать сокет для соединений. Первый аргумент — это дескриптор файла сокета, а второй — размер невыполненной очереди, т. е. количество соединений, которые могут находиться в ожидании, пока процесс обрабатывает конкретное соединение. Это должно быть установлено на 5, максимальный размер, разрешенный большинством систем. Если первый аргумент является допустимым сокетом, этот вызов не может завершиться ошибкой, поэтому код не проверяет наличие ошибок. Щелкните здесь, чтобы увидеть справочную страницу для прослушивания. Системный вызов accept() блокирует процесс до тех пор, пока клиент не подключится к серверу. Таким образом, он пробуждает процесс, когда соединение от клиента успешно установлено. Он возвращает новый файловый дескриптор, и вся связь по этому соединению должна осуществляться с использованием нового файлового дескриптора. Второй аргумент — указатель на адрес клиента на другом конце соединения, а третий аргумент — размер этой структуры. Обратите внимание, что мы доберемся до этой точки только после того, как клиент успешно подключится к нашему серверу. Этот код инициализирует буфер с помощью функции bzero(), а затем читает из сокета. Обратите внимание, что вызов чтения использует новый файловый дескриптор, возвращенный accept() , а не исходный файловый дескриптор, возвращенный socket() . Также обратите внимание, что read() будет блокироваться до тех пор, пока в сокете не появится что-то для чтения, т.е. после того, как клиент выполнил write() . Он прочитает либо общее количество символов в сокете, либо 255, в зависимости от того, что меньше, и вернет количество прочитанных символов. Нажмите здесь, чтобы увидеть справочную страницу для read() . Как только соединение установлено, оба конца могут как читать, так и писать в соединение. Естественно, все, что пишет клиент, будет прочитано сервером, а все, что написано сервером, будет прочитано клиентом. Этот код просто пишет короткое сообщение клиенту. Последний аргумент write — это размер сообщения. Нажмите здесь, чтобы увидеть справочную страницу для записи. Это завершает работу main и, следовательно, программы.

Читайте также:
Лучшие дисковые пилы 2022 года — This Old House

Код клиента

Как и прежде, мы пройдемся по программе client.c построчно. Заголовочные файлы такие же, как и для сервера с одним дополнением. Файл netdb.h определяет структуру hostent, которая будет использоваться ниже. Функция error() идентична таковой на сервере, как и переменные sockfd, portno и n. Переменная serv_addr будет содержать адрес сервера, к которому мы хотим подключиться. Он имеет тип struct sockaddr_in .

Переменная server является указателем на структуру типа hostent. Эта структура определена в заголовочном файле netdb.h следующим образом: Она определяет хост-компьютер в Интернете. Членами этой структуры являются: Обратите внимание, что h_addr является псевдонимом для первого адреса в массиве сетевых адресов. Весь этот код такой же, как и на сервере. argv[1] содержит имя хоста в Интернете, например, cheerios@cs.rpi.edu. Функция: принимает такое имя в качестве аргумента и возвращает указатель на хост, содержащий информацию об этом хосте. Поле char *h_addr содержит IP-адрес. Если эта структура имеет значение NULL, система не может найти хост с таким именем.

Механизм, с помощью которого работает эта функция, сложен и часто включает запросы к большим базам данных по всей стране. Этот код устанавливает поля в serv_addr. Многое там такое же, как и на сервере. Однако, поскольку поле server->h_addr представляет собой строку символов, мы используем функцию: которая копирует байты длины из s1 в s2. Функция подключения вызывается клиентом для установления соединения с сервером. Он принимает три аргумента: дескриптор файла сокета, адрес хоста, к которому он хочет подключиться (включая номер порта), и размер этого адреса. Эта функция возвращает 0 в случае успеха и -1 в случае неудачи. Нажмите здесь, чтобы увидеть справочную страницу для подключения.

Обратите внимание, что клиенту необходимо знать номер порта сервера, но ему не обязательно знать номер собственного порта. Обычно это назначается системой при вызове соединения. Оставшийся код должен быть достаточно четким. Он предлагает пользователю ввести сообщение, использует fgets для чтения сообщения со стандартного ввода, записывает сообщение в сокет, читает ответ из сокета и отображает этот ответ на экране.

Читайте также:
Сколько стоит замена крыши в 2022 году?

Улучшения в коде сервера

Приведенный выше пример кода сервера имеет ограничение, заключающееся в том, что он обрабатывает только одно соединение, а затем умирает. Сервер «реального мира» должен работать бесконечно и должен иметь возможность обрабатывать несколько одновременных подключений, каждое в своем собственном процессе. Обычно это делается путем создания нового процесса для обработки каждого нового соединения.

В следующем коде есть фиктивная функция с именем dostuff(int sockfd) . Эта функция будет обрабатывать соединение после того, как оно будет установлено, и предоставлять любые услуги, которые запрашивает клиент. Как мы видели выше, как только соединение установлено, оба конца могут использовать чтение и запись для отправки информации другому концу, и детали информации, передаваемой туда и обратно, нас здесь не касаются. Чтобы написать «реальный» сервер, вам не нужно будет вносить практически никаких изменений в функцию main(), и весь код, предоставляющий эту услугу, будет находиться в dostuff().

Установка сетевого сокета – пошаговое руководство

Используйте кабельный нож WEICON TOOLS № 35, чтобы укоротить сетевой кабель (кат. 7), если это необходимо. Если кабель слишком длинный, его будет трудно убрать в коробку для полых стен.

Зачистка сетевого кабеля

Если вы хотите установить классическую сетевую розетку, вы должны сначала удалить Cat. 7 кабель. Здесь используется специальный инструмент для зачистки дата-кабелей — например, Стриппер № 2 кат. Используйте сторону A, чтобы снять защитную оболочку. Проводники не могут быть повреждены благодаря точной настройке лезвия. Пожалуйста, не удаляйте экранирующую оплетку, которая теперь видна, а аккуратно оберните ее вокруг кабеля.

На следующем этапе снимите экран из фольги, который окружает отдельные жилы так называемой витой пары. Для этого используйте сторону B инструмента для зачистки и убедитесь, что зачистите только несколько сантиметров. Вы должны удалить остатки фольги как можно позже.

Структура сетевого кабеля

Наденьте Кота. 7 кабель

Теперь возьмите монтажную пластину сетевой розетки, а также отвертку, поместите кабель с небольшой ловкостью в предусмотренный фиксатор и затяните его.

Теперь следует небольшая игра цветов: на печатной плате сетевой розетки цветовой код указывает последовательность, в которой должны быть подключены отдельные провода. Вы также можете обратиться к плану назначения производителя. Следуете ли вы цветовой схеме A или B, зависит от того, какой тип назначения использовался в доме до сих пор. Важно, чтобы вы взяли тот же самый снова! В этом примере мы уложили отдельные жилы по типу В.

Читайте также:
Горизонтальная проточная печь - BuildOps

Предварительно разберите пары проводов, возьмите печатную плату сетевой розетки и проведите провода через печатную плату вперед в обозначенных точках. Теперь удалите оставшуюся часть слоя и скрутите пары проводов.

Установите сетевой сокет с помощью инструмента для укладки LSA

На следующем этапе вступает в игру решающий инструмент – инструмент для укладки АЛП или инструмент для укладки АЛП. С помощью такого инструмента и небольшого давления вы постепенно вдавливаете отдельные провода в разъемы смещения изоляции в соответствии с цветовой маркировкой. Инструмент автоматически удаляет излишки кабеля.

Установить сетевой сокет

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

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: