Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Возможности тулкита GTK+ и сопутствующих библиотек

Низкоуровневые функции для работы с сетью

Автор: A. Панин
Дата публикации: 11 июня 2015 г.

Современные приложения с графическим интерфейсом все чаще используют сетевые сервисы. Несмотря на то, что в приложениях с графическим интерфейсом на основе тулкита GTK+ могут вполне успешно применяться вызовы функций API Linux для работы с сетевыми сокетами, в рамках библиотеки GIO реализованы классы, позволяющие разрабатывать кроссплатформенные сетевые приложения. Бесспорным преимуществом упомянутых классов является тесная интеграция с механизмами, реализованными в рамках библиотеки GLib, среди которых следует особо выделить главный цикл обработки событий. Вообще говоря, набор классов, связанных с разработкой сетевых приложений в рамках библиотеки GIO достаточно обширен, поэтому в данной статье мы затронем лишь низкоуроневые функции для работы с сетью, реализованные в рамках класса GSocket а также механизм разрешения доменных имен, реализованный в рамках класса GResolver. Рассмотренных функций будет вполне достаточно для разработки как приведенных в статье простейших клиентских приложений, обменивающихся данными с сетевыми серверами по протоколам TCP и UDP, так и сложных приложений, использующих помимо упомянутых протоколов относительно новый протокол SCTP. Также в рамках библиотеки GLib реализованы более высокоуровневые классы для разработки сетевых приложений, о которых мы, возможно, поговорим в следующих статьях серии.

1. Класс сетевого сокета GSocket

Класс сетевого сокета GSocket упрощает работу с сетевым сокетом в случае использования библиотеки GIO и реализует множество методов для управления состоянием этого сокета. Объект типа GSocket может быть создан с помощью конструктора g_socket_new(), а также с помощью специализированного конструктора g_socket_new_from_fd(), причем в качестве аргумента последнего конструктора должен использоваться целочисленный дескриптор уже существующего сетевого сокета.

GSocket * g_socket_new(GSocketFamily family, 
                       GSocketType type,
                       GSocketProtocol protocol,
                       GError **error);
GSocket * g_socket_new_from_fd(gint fd,
                               GError **error);

В случае неудачной попытки создания объекта сетевого сокета оба конструктора возвращают значение NULL и передают объект ошибки типа GError с дополнительной информацией о возникшей ошибке. Если в случае второго конструктора единственным входным параметром является дескриптор действующего сокета, то в случае первого конструктора не все так очевидно, ведь требуется передать идентификаторы семейства протоколов, типа сокета и протокола. Допустимые идентификаторы с описаниями приведены в таблицах ниже.

Таблица 1 - Семейства протоколов сетевых сокетов

Семейство протоколов в рамках библиотеки GIO Семейство протоколов в рамках системного API Описание
G_SOCKET_FAMILY_INVALID - Не установлено
G_SOCKET_FAMILY_UNIX AF_UNIX Семейство протоколов домена UNIX
G_SOCKET_FAMILY_IPV4 AF_INET Семейство протоколов IPv4
G_SOCKET_FAMILY_IPV6 AF_INET6 Семейство протоколов IPv6

Таблица 2 - Типы сетевых сокетов

Тип сетевого сокета в рамках библиотеки GIO Тип сетевого сокета в рамках системного API Описание
G_SOCKET_TYPE_INVALID - Неизвестный или некорректный тип
G_SOCKET_TYPE_STREAM SOCK_STREAM Сокет для надежной передачи байтового потока с установлением соединения (по протоколу TCP)
G_SOCKET_TYPE_DATAGRAM SOCK_DGRAM Сокет для ненадежной передачи дейтаграмм без установления соединения (по протоколу UDP)
G_SOCKET_TYPE_SEQPACKET SOC_SEQPACKET Сокет для надежной передачи дейтаграмм фиксированного максимального размера с установлением соединения (по протоколу SCTP)

Таблица 3 - Протоколы сетевых сокетов

Протокол сетевого сокета в рамках библиотеки GIO Описание
G_SOCKET_PROTOCOL_UNKNOWN Тип протокола неизвестен
G_SOCKET_PROTOCOL_DEFAULT Стандартный протокол для заданного семейства протоколов/типа сетевого сокета
G_SOCKET_PROTOCOL_TCP TCP/IP
G_SOCKET_PROTOCOL_UDP UDP/IP
G_SOCKET_PROTOCOL_SCTP SCTP/IP

В большинстве случаев в качестве идентификатора протокола сетевого сокета может безопасно передаваться идентификатор стандартного протокола для заданного семейства/типа сетеврго сокета (G_SOCKET_PROTOCOL_DEFAULT).

После создания объекта сетевого сокета активируется режим блокируемого ввода-вывода, который эмулируется на уровне библиотеки GIO, а не активиурется на уровне системы. Для нового сетевого сокета на уровне системы в любом случае активируется режим неблокируемого ввода-вывода. Такой режим работы сетевого сокета необходим для корректной интеграции в главный цикл обработки событий приложения, причем на уровне библиотеки GIO для изменения режима ввода-вывода может быть использован метод g_socket_set_blocking(), а для получения информация о режиме ввода-вывода объекта сетевого сокета - метод g_socket_get_blocking():

void
g_socket_set_blocking(GSocket *socket,
                      gboolean blocking);
gboolean
g_socket_get_blocking(GSocket *socket);

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

Для мультиплексирования ввода-вывода вместо специальных функций (select(), poll(), epoll()) может использоваться как главный цикл обработки событий, так и цикл обработки событий из любого программного потока, созданного в рамках приложения. В случае необходимости мультиплексирования ввода-вывода может оказаться полезным как метод g_socket_create_source (), предназначенный для создания нового источника событий, который впоследствии может использоваться совместно с главным циклом обработки событий, так и методы g_socket_condition_check(), g_socket_condition_wait() и g_socket_condition_timed_wait(), предназначенные для проверки состояния сетевого сокета и ожидания его перехода в заданное состояние (без указания и с указанием максимального периода ожидания соотвественно).

GSource * 
g_socket_create_source(GSocket *socket,
                       GIOCondition condition,
                       GCancellable *cancellable);
GIOCondition
g_socket_condition_check(GSocket *socket,
                         GIOCondition condition);
gboolean
g_socket_condition_wait(GSocket *socket,
                        GIOCondition condition,
                        GCancellable *cancellable,
                        GError **error);
gboolean
g_socket_condition_timed_wait(GSocket *socket,
                              GIOCondition condition,
                              gint64 timeout,
                              GCancellable *cancellable,
                              GError **error);

Два из трех приведенных выше методов мультиплексирования ввода-вывода принимают в качестве аргумента объект отмены операции для многопоточного приложения типа GCancellable. Данный объект создается с помощью конструктора g_cancellable_new(), а непосредственная отмена операции осуществляется с помощью его метода g_cancellable_cancel(). Если вы не планируете прерывать операции установки соединений и обмена данными посредством сетевых сокетов, вы можете передавать значения NULL вместо объектов отмены операций упомянутого типа.

GCancellable *
g_cancellable_new(void);
void
g_cancellable_cancel(GCancellable *cancellable);

Во всех приведенных выше методах мультиплексирования ввода-вывода используются битовые маски условий операций ввода-вывода типа GIOCondition. Допустимые значения условий операций ввода-вывода с соответствующими константами условий функции poll() приведены в следующей таблице.

Таблица 4 - Условия операций ввода-вывода

Условие в рамках библиотеки GIO Условие функции poll() Описание
G_IO_IN POLLIN Данные доступны для чтения
G_IO_OUT POLLOUT Данные могут быть записаны без блокировки
G_IO_PRI POLLPRI Приоритетные данные доступны для чтения
G_IO_ERR POLLERR Произошла ошибка
G_IO_HUP POLLHUP Произошел обрыв соединения
G_IO_NVAL POLLNVAL Некорректная операция, дескриптор сокета не был открыт.

При задании битовой маски условий операций ввода-вывода не следует использовать условия G_IO_ERR и G_IO_HUP, так как их наступление будет отмечено в любом случае. Пример использования метода для создания источника событий g_socket_create_source() с последующей обработкой событий в рамках основного цикла обработки событий приложения будет приведен позднее в рамках данной статьи. В случае истечения заданного периода ожидания будет возвращаться заданное условие операции ввода вывода, но после использования метода для обмена данными будет возвращаться ошибка с идентификатором G_IO_ERROR_TIMED_OUT. Метод для проверки состояния сетевого сокета g_socket_condition_check() никогда не блокируется. Методы ожидания перехода сетевого сокета в заданное состояние g_socket_condition_wait() и g_socket_condition_timed_wait() возвращают логическое значение TRUE в случае успешного перехода сокета в заданное состояние и FALSE в случае истечения установленного времени ожидания или принудительной отмены операции ожидания (с возвратом объектов ошибок с идентификаторами G_IO_ERROR_TIMED_OUT и G_IO_ERROR_CANCELLED соответственно).

Благодаря эмуляции режима блокируемого ввода-вывода на уровне библиотеки GIO становится возможной установка времени ожидания завершения операций с сетевыми сокетами. Время ожидания завершения операций для объекта сетевого сокета в секундах может быть установлено с помощью метода g_socket_set_timeout() и получено с помощью метода g_socket_get_timeout().

void
g_socket_set_timeout(GSocket *socket,
                     guint timeout);
guint
g_socket_get_timeout(GSocket *socket);

В том случае, если для сетевого сокета активирован режим блокируемого ввода-вывода, все блокирующие операции будут завершаться по истечении заданного периода времени с возвратом объекта ошибки с идентификатором G_IO_ERROR_TIMED_OUT. В случае использования режима неблокируемого ввода-вывода объекты ошибок с упомянутым идентификатором будут возвращаться по истечении заданного периода времени при работе с методом ожидания перехода сокета в заданное состояние (g_socket_condition_wait()) и при использовании функций для обмена данными посредством сокета (причем перед возвратом объекта ошибки в случае обработки событий сокета в рамках основного цикла обработки событий приложения будут возвращаться идентификаторы заданных условий). Для того, чтобы отказаться от использования описанного механизма следует всего лишь передать значение 0 в качестве аргумента timeout метода g_socket_set_timeout().

Для соединения с удаленным узлом должен использоваться метод g_socket_connect(). Данный метод может использоваться как при работе с протоколами, предусматривающими установку соединения (такими, как TCP), так и с протоколами, не предусматривающими установки соединения (такими, как UDP), причем в случае использования первого типа протоколов данный метод может вызываться лишь один раз, а в случае использования второго типа протоколов - множество раз для с целью задания нового адреса для отправки и приема дейтаграмм. При активации режима блокируемого ввода-вывода использование данного метода может приводить к блокировке, а в случае активации режима неблокируемого ввода-вывода может возвращаться объект ошибки с идентификатором G_IO_ERROR_PENDING, причем в этом случае момент установки соединения может отслеживаться по наступлению состояния записи данных без блокировки (G_IO_OUT), а корректность установки соединения может проверяться с помощью метода g_socket_check_connect_result().

gboolean
g_socket_connect(GSocket *socket,
                 GSocketAddress *address,
                 GCancellable *cancellable,
                 GError **error);
gboolean
g_socket_check_connect_result(GSocket *socket,
                              GError **error);

Следует также обратить внимание на объект адреса сокета GSocketAddress, используемый в качестве аргумента метода g_socket_connect(). На самом деле следует использовать объект на основе класса GInetSocketAddress при работе с сетевыми сокетами и на основе класса GUnixSocketAddress при работе с сокетами домена UNIX. Объект на основе первого класса может создаваться как на основе объекта сетевого адреса на основе класса GSocketAddress с указанием номера порта путем использования конструктора g_inet_socket_address_new(), так и на основе строковой записи адреса узла и целочисленного номера порта путем использования конструктора g_inet_socket_address_new_from_string(). Объект на основе второго класса создается с помощью конструктора g_unix_socket_address_new().

GSocketAddress *
g_inet_socket_address_new(GInetAddress *address,
                          guint16 port);
GSocketAddress *
g_inet_socket_address_new_from_string(const char *address,
                                      guint port);
GSocketAddress *
g_unix_socket_address_new(const gchar *path);

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

gboolean
g_socket_bind(GSocket *socket,
              GSocketAddress *address,
              gboolean allow_reuse,
              GError **error);

Аргумент allow_reuse позволяет произвести установку значения параметра SO_REUSEADDR сетевого сокета сразу же после присваивания адреса этому сокету. В большинстве случаев следует использовать значение TRUE при разработке приложений, принимающих соединения, и FALSE при разработке приложений, инициирующих соединения. Возврат объекта ошибки с идентификатором G_IO_ERROR_ADDRESS_IN_USE при использовании метода g_socket_bind() после перезапуска приложения, принимающего соединения, является главным признаком некорректной установки значения данного аргумента.

Для перевода сетевого сокета в режим приема соединений после присваивания этому сокету адреса следует использовать метод g_socket_listen(). Длина очереди запросов соединений может устанавливаться с помощью метода g_socket_set_listen_backlog() и извлекаться с помощью метода g_socket_get_listen_backlog().

gboolean
g_socket_listen(GSocket *socket,
                GError **error);
void
g_socket_set_listen_backlog(GSocket *socket,
                            gint backlog);
gint
g_socket_get_listen_backlog(GSocket *socket);

Для непосредственного приема соединений после перевода сетевого сокета в соответствующий режим может использоваться метод g_socket_accept(). В том случае, если в очереди запросов соединений имеются запросы, первый запрос будет извлечен из нее, а функция вернет новый объект сетевого сокета типа GSocket. В том же случае, если очередь запросов соединений пуста, вызов рассматриваемого метода приведет к блокировке при активации режима блокируемого ввода-вывода или к возврату объекта ошибки с идентификатором G_IO_ERROR_WOULD_BLOCK в противном случае. Поступление запросов соединений может отслеживаться по наступлению состояния доступности данных для чтения (G_IO_IN).

GSocket *
g_socket_accept(GSocket *socket,
                GCancellable *cancellable,
                GError **error);

Прием данных посредством сетевого сокета может осуществляться с помощью методов g_socket_receive(), g_socket_receive_from(), g_socket_receive_message() и g_socket_receive_with_blocking().

gssize
g_socket_receive(GSocket *socket,
                 gchar *buffer,
                 gsize size,
                 GCancellable *cancellable,
                 GError **error);
gssize
g_socket_receive_from(GSocket *socket,
                      GSocketAddress **address,
                      gchar *buffer,
                      gsize size,
                      GCancellable *cancellable,
                      GError **error);
gssize
g_socket_receive_message(GSocket *socket,
                         GSocketAddress **address,
                         GInputVector *vectors,
                         gint num_vectors,
                         GSocketControlMessage ***messages,
                         gint *num_messages,
                         gint *flags,
                         GCancellable *cancellable,
                         GError **error);
gssize
g_socket_receive_with_blocking(GSocket *socket,
                               gchar *buffer,
                               gsize size,
                               gboolean blocking,
                               GCancellable *cancellable,
                               GError **error);

Первый метод g_socket_receive() является наиболее простым и предназначен для приема данных посредством соединенного сетевого сокета. С помощью аргумента buffer передается указатель на область памяти, в которую будут скопированы принятые данные, а с помощью аргумента size - размер этой области. При работе с протоколами, предусматривающими передачу дейтаграмм, с помощью рассматриваемого метода может быть принята либо одна дейтаграмма, либо не принято дейтаграмм вообще, причем в случае недостаточного размера фрагмента памяти принятая дейтаграмма будет урезана. При работе с протоколами, предусматривающими передачу потока данных, с помощью данного метода может быть принят любой объем данных, не превышающий переданный размер фрагмента памяти. Данный метод аналогичен системной функции recv(). При активации режима блокируемого ввода-вывода и отсутствии данных для приема вызов метода может повлечь за собой блокировку, а при активации режима неблокируемого ввода-вывода - возврат объекта ошибки с идентификатором G_IO_ERROR_WOULD_BLOCK. Отслеживание появления данных для приема может осуществляться по наступлению соответствующего состояния (G_IO_IN). Метод возвращает количество принятых байт, значенние 0 в случае закрытия соединения на на другой строне или значение -1 в случае ошибки. Второй метод g_socket_receive_from() предназначен для приема данных посредством несоединенного сетевого сокета. Он работает аналогично первому методу, но позволяет задать адрес узла для приема данных или принять данные с произвольного узла. По сути данный метод является аналогом системной функции recvfrom(). Третий метод является самым мощным и чаще всего используется для работы с сокетами домена UNIX и Netlink-сокетами. Данный метод предполагает использование наборов векторов ввода типа GInputVector (являющихся простыми буферами с указанной длиной) и передаваемых посредством ядра ОС управляющих сообщений типа GSocketControlMessage (к примеру, наборов файловых дескрипторов или пользовательских прав). Кроме того, вы можете задействовать аргумент flags для указания флагов, к примеру, с целью передачи внеполосных данных. Данный метод является упрощенным аналогом системной функции recvmsg(). Последний метод полностью аналогичен первому, за исключением того, что вы можете активировать режим блокируемого или неблокируемого ввода-вывода для отдельной операции с помощью аргумента blocking.

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

gssize
g_socket_get_available_bytes(GSocket *socket);

Отправка данных по аналогии с приемом данных может осуществляться с помощью четырех методов, а именно: g_socket_send(), g_socket_send_to(), g_socket_send_message() и g_socket_send_with_blocking().

gssize
g_socket_send(GSocket *socket,
              const gchar *buffer,
              gsize size,
              GCancellable *cancellable,
              GError **error);
gssize
g_socket_send_to(GSocket *socket,
                 GSocketAddress *address,
                 const gchar *buffer,
                 gsize size,
                 GCancellable *cancellable,
                 GError **error);
gssize
g_socket_send_message(GSocket *socket,
                      GSocketAddress *address,
                      GOutputVector *vectors,
                      gint num_vectors,
                      GSocketControlMessage **messages,
                      gint num_messages,
                      gint flags,
                      GCancellable *cancellable,
                      GError **error);
gssize
g_socket_send_with_blocking(GSocket *socket,
                            const gchar *buffer,
                            gsize size,
                            gboolean blocking,
                            GCancellable *cancellable,
                            GError **error);

По аналогии с методами для приема данных с помощью аргумента buffer передается указатель на область памяти с данными, которые необходимо передать посредством сетевого сокета, а с помощью аргумента size - задается объем этих данных. Первый метод (g_socket_send()) используется главным образом при работе с протоколами, предусматривающими установку соединения, и аналогичен системной функции send(). В случае активации режима блокируемого ввода-вывода и недостатка места в очереди отправки данный метод будет блокироваться до момента передачи данных из этой очереди в объеме, достаточном для копирования переданных данных в нее. При активации режима неблокируемого ввода-вывода в аналогичной ситуации будет возвращен объект ошибки с идентификатором G_IO_ERROR_WOULD_BLOCK. Для отслеживания моментов освобождения места в очереди отправки сетевого сокета следует ожидать наступления соотествующего состояния (G_IO_OUT), причем даже после его наступления в некоторых случаях вы можете столкнуться с ранее упомянутой ошибкой с идентификатором G_IO_ERROR_WOULD_BLOCK. Метод возвращает количество отправленных байт или значение -1 в случае ошибки. Второй метод (g_socket_send_to()) очень похож на первый, но используется главным образом при работе с протоколами, не предусматривающими установки соединения, и аналогичен системной функции sendto(). С помощью аргумента address задается адрес целевого узла для отправки данных. Третий метод (g_socket_send_message()) является самым мощным методом для отправки данных посредством сетевого сокета и предусматривает возможность передачи данных, упакованных в векторы вывода типа GOutputVector, передачи управляющих сообщений типа GSocketControlMessage, а также установки флагов сообщений. Как и соответствующий метод приема данных, данный метод используется главным образом при работе с сокетами домена UNIX, Netlink-сокетами, а также в случае необходимости установки флагов. Данный метод является упрощенным вариантом системной функции sendmsg(). Последний метод (g_socket_send_with_blocking()) полностью аналогичен первому методу за исключением того, что вы можете активировать режим блокируемого или неблокируемого ввода-вывода на уровне отдельной операции с помощью аргумента blocking.

В некоторых случаях при разработке сетевых приложений приходится задавать параметры сокетов, причем в случае работы с системным API сокетов для этих целей используются функции setsockopt() и getsockopt(). Библиотека GIO, в свою очередь, предлагает разработчику методы g_socket_set_option() и g_socket_get_option() для установки и получения целочисленных значений произвольных параметров сокетов, а также множество специализированных методов для установки и получения значений наиболее востребованных нечисловых параметров.

gboolean
g_socket_set_option(GSocket *socket,
                    gint level,
                    gint optname,
                    gint value,
                    GError **error);
gboolean
g_socket_get_option(GSocket *socket,
                    gint level,
                    gint optname,
                    gint *value,
                    GError **error);

С помощью аргумента level задается "уровень API" (SOL_SOCKET, IPPROTO_IP, IPPROTO_ICMPV6, IPPROTO_IPV6, IPPROTO_TCP), с помощью аргумента optname - идентификатор параметра, а с помощью аргумента value - целочисленное значение параметра. В том случае, если необходимо установить или получить значение параметра сокета, не являющееся целочисленным, следует использовать непосредственно функции setsockopt() и getsockopt(). Для получения доступа к объявлениям идентификаторов уровней API и параметров следует подключить либо заголовочный файл <gio/gnetworking.h>, либо необходимые системные заголовочные файлы.

Управление механизмом проверки работоспособности соединения может осуществляться с помощью специализированного метода g_socket_set_keepalive(), а проверка состояния этого механизма - с помощью метода g_socket_get_keepalive(). Разумеется, данный механизм работоспособен исключительно в случае использования протокола, предусматривающего установку соединения, например, протокола TCP. Интервал проверок зависит от реализации сетевого стека и выбранного протокола и может изменяться сразу для всех сетевых сокетов в рамках системы.

void
g_socket_set_keepalive(GSocket *socket,
                       gboolean keepalive);
gboolean
g_socket_get_keepalive(GSocket *socket);

Время жизни отправленных посредством сокета сетевых пакетов пакетов может быть установлено с помощью метода g_socket_set_ttl() и получено с помощью метода g_socket_get_ttl().

void
g_socket_set_ttl(GSocket *socket,
                 guint ttl);
guint
g_socket_get_ttl(GSocket *socket);

Возможность отправки многоадресных дейтаграмм может быть активирована с помощью метода g_socket_set_broadcast() и проверена с помощью метода g_socket_get_broadcast().

void
g_socket_set_broadcast(GSocket *socket,
                       gboolean broadcast);
gboolean
g_socket_get_broadcast(GSocket *socket);

Существует и несколько методов, относящихся к режиму многоадресной передачи данных. Время жизни пакетов в случае многоадресной передачи, может быть задано с помощью метода g_socket_set_multicast_ttl() и получено с помощью метода g_socket_get_multicast_ttl(). Режим передачи копий пакетов на узел, с которого они были переданы, может быть изменен с помощью метода g_socket_set_multicast_loopback() и получен с помощью метода g_socket_get_multicast_loopback().

void
g_socket_set_multicast_ttl(GSocket *socket,
                           guint ttl);
guint
g_socket_get_multicast_ttl(GSocket *socket);
void
g_socket_set_multicast_loopback(GSocket *socket,
                                gboolean loopback);
gboolean
g_socket_get_multicast_loopback(GSocket *socket);

Для присоединения к группе многоадресной передачи и выхода из нее могут использоваться методы g_socket_join_multicast_group() и g_socket_leave_multicast_group() соответственно.

gboolean
g_socket_join_multicast_group(GSocket *socket,
                              GInetAddress *group,
                              gboolean source_specific,
                              const gchar *iface,
                              GError **error);
gboolean
g_socket_leave_multicast_group(GSocket *socket,
                               GInetAddress *group,
                               gboolean source_specific,
                               const gchar *iface,
                               GError **error);

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

Существуют и дополнительные методы, позволяющие получить параметры сетевого сокета. Метод g_socket_get_family() позволяет получить идентификатор семейства протоколов, с которым работает сетевой сокет, метод g_socket_get_fd() - дескриптор или хэндл сетевого сокета, метод g_socket_get_local_address() - локальный адрес связанного сетевого сокета, метод g_socket_get_remote_address() - удаленный адрес связанного сетевого сокета, метод g_socket_get_protocol() - идентификатор протокола, который используется сетевым сокетом, метод g_socket_get_socket_type() - идентификатор типа сетевого сокета, метод g_socket_speaks_ipv4() - информацию о возможности работы с протоколом IPv4 при условии использования сетевого сокета.

GSocketFamily
g_socket_get_family(GSocket *socket);
int
g_socket_get_fd(GSocket *socket);
GSocketAddress *
g_socket_get_local_address(GSocket *socket,
                           GError **error);
GSocketAddress *
g_socket_get_remote_address(GSocket *socket,
                            GError **error);
GSocketProtocol
g_socket_get_protocol(GSocket *socket);
GSocketType
g_socket_get_socket_type(GSocket *socket);
gboolean
g_socket_speaks_ipv4(GSocket *socket);

Так как класс сетевого сокета GSocket является классом, унаследованным от класса GObject, он использует счетчик ссылок, значение которого равно 1 при создании объекта. При достижении нулевого значения счетчика ссылок сетевой сокет будет автоматически закрыт, а объект сетевого сокета - уничтожен. Для установки и удаления ссылок на объект могут использоваться стандартные методы g_object_ref() и g_object_unref(). Кроме того, существует метод g_socket_close() для явного закрытия сетевого сокета, метод g_socket_is_closed() для проверки корректности его закрытия и метод g_socket_shutdown() для частичного или полного прекращения полнодуплексной передачи данных посредством сетевого сокета.

gboolean
g_socket_close(GSocket *socket,
               GError **error);
gboolean
g_socket_is_closed(GSocket *socket);
gboolean
g_socket_shutdown(GSocket *socket,
                  gboolean shutdown_read,
                  gboolean shutdown_write,
                  GError **error);

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

Как вы могли заметить, названия методов очень похожи на названия системных функций API сокетов, следовательно, все описанные в различной литературе приемы сетевого программирования могут с успехом применяться и в случае разработки сетевых приложений на основе библиотек GLib/GIO.


Продолжение статьи : 2. Класс системы разрешения доменных имен GResolver.