Все типы struct sockaddr
соответствуют приведенному ниже определению.
#include
struct sockaddr {
unsigned short sa_family;
char sa_data[MAXSOCKADDRDATA];
}
Первые два байта (размер short
) указывают семейство адресов, к которому относится данный адрес. Перечень стандартных адресных семейств, используемых приложениями Linux, приведен в табл. 17.1.
Таблица 17.1. Семейства протоколов и адресов
Адрес |
Протокол |
Описание протокола |
AF_UNIX |
PF_UNIX |
Домен Unix. |
AF_INET |
PF_INET |
TCP/IP (версия 4). |
AF_INET6 |
PF_INET6 |
TCP/IP (версия 6). |
AF_AX25 |
PF_AX25 |
AX.25, используется радиолюбителями. |
AF_IPX |
PF_IPX |
Novell IPX. |
AF_APPLETALK |
PF_APPLETALK |
AppleTalk DDS. |
AF_NETROM |
PF_NETROM |
NetROM, используется радиолюбителями. |
Во всех примерах этого раздела используются две функции: copyData()
и die()
. Функция copyData()
считывает данные из одного файлового дескриптора и записывает их в какой-то другой дескриптор (до тех пор, пока имеются данные для чтения). Функция die()
вызывает perror()
и завершает программу. Мы ввели обе указанные функции в файл sockutil.с
для того, чтобы сделать обучающие программы немного проще. Для справки ниже показана реализация двух данных функций.
1: /* sockutil.с */
2:
3: #include
4: #include
5: #include
6:
7: #include "sockutil.h"
8:
9: /* выдает сообщение об ошибке через функцию perror() и прекращает работу программы */
10: void die(char * message) {
11: perror(message);
12: exit(1);
13: }
14:
15: /* Копирует данные из дескриптора файла 'from' в дескриптор файла
16: 'to' до полного завершения копирования. Выходит из программы, если
17: происходит ошибка. Предполагается, что для обоих файлов установлено
18: блокирующее чтение и запись. */
19: void copyData(int from, int to) {
20: char buf[1024];
21: int amount;
22:
23; while ((amount = read(from, buf, sizeof(buf))) > 0) {
24: if (write(to, buf, amount) != amount) {
25: die("write");
26: return;
27: }
28: }
29: if (amount < 0)
30: die("read");
31: }
17.3. Основные действия с сокетами
Подобно большинству остальных ресурсов Linux сокеты реализуются через файловую абстракцию. Они создаются при помощи системного вызова socket()
, который возвращает файловый дескриптор. После соответствующей инициализации сокета данный дескриптор может использоваться для запросов read()
и write()
, как и любой другой файловый дескриптор. Когда процесс завершает работу с сокетом, его необходимо закрыть через функцию close()
для того, чтобы освободить все ресурсы, ассоциированные с ним.
В настоящем разделе представлены основные системные вызовы для создания и инициализации сокетов для любого протокола. Для того чтобы не зависеть от протоколов, информация в некоторой степени абстрагирована, по этой же причине мы не приводим примеры. Следующие два раздела посвящены применению сокетов в двух различных протоколах (домен Unix и TCP/IP). Здесь вы найдете подробные примеры использования большинства системных вызовов, описанных ниже.
Новые сокеты создаются системным вызовом socket()
, который возвращает файловый дескриптор для неинициализированного сокета. При создании сокет привязывается к определенному протоколу, однако соединение для сокета не устанавливается. На данном этапе еще невозможно считывать информацию из сокета и записывать в него.
#include
int socket(int domain, int type, int protocol);
Подобно open()
, функция socket()
возвращает значение меньше 0, если имела место ошибка, и файловый дескриптор, больший или равный нулю, если все прошло благополучно. Три параметра устанавливают протокол, который нужно использовать.
Первый параметр указывает семейство протоколов и, как правило, принимает одно из значений, перечисленных в табл. 17.1.
Следующий параметр type
может иметь одно из значений: SOCK_STREAM
, SOCK_DGRAM
или SOCK_RAW
. [119] Допустимы еще несколько значений данного параметра, однако они редко применяются в коде приложений.
Здесь SOCK_STREAM
указывает потоковый протокол из данного семейства, a SOCK_DGRAM
специфицирует дейтаграммный протокол из того же семейства. Параметр SOCK_RAW
предоставляет возможность передавать пакеты прямо в драйвер сетевого устройства, что позволяет пользовательским приложениям поддерживать сетевые протоколы, которые не воспринимаются ядром.
Читать дальше