ggp 3 GGP # Протокол GGP (gateway-gateway )
tcp 6 TCP # Протокол TCP
udp 17 UDP # Протокол UDP
Если сокет создан успешно, функция возвращает дескриптор сокета — целое положительное число. В случае ошибки функция возвращает значение -1 (отрицательное число). Вот небольшой пример:
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock==-1) {
printf('Ошибка при создании сокета
');
exit(1);
}
Чтобы связать созданный нами сокет с локальным портом, например, 1234, нужно использовать системный вызов bind():
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
extern int bind(int fd, struct sockaddr *addr,
socklen_t len) __THROW;
Первый аргумент функции задает дескриптор нашего сокета. Второй — это указатель на структуру типа sockaddr. Все структуры данного типа определены в файле socket.h
:
# define __SОСKADDR_ALLTYPES
__SOCKADDR_ONETYPE (sockaddr)
__SOCKADDR_ONETYPE (sockaddr_at)
__SОСKADDR_ONETYPE (sockaddr_ax25)
__SOCKADDR_ONETYPE (sockaddr_dl)
__SOCKADDR_ONETYPE (sockaddr_eon)
__SОСKADDR_ONETYPE (sockaddr_in)
__SOCKADDR_ONETYPE (sockaddr_in6)
__SОСKADDR_ONETYPE (sockaddr_inarp)
__SOCKADDR_ONETYРЕ (sockaddr_ipx)
__SОСKADDR_ONETYPE (sockaddr_iso)
__SОСKADDR_ONETYPE (sockaddr_ns)
__SOCKADDR_ONETYPE (sockaddr_un)
__SOCKADDR_ONETYPE (sockaddr_x25)
Мы программируем для сети TCP/IP, поэтому будем использовать структуру sockaddr_in (для IPv4) или sockaddr_in6 (для IPv6).
Последний аргумент — это длина выбранной нами структуры (sockaddr_in) в байтах.
Структура sockaddr_in определена в файле in.h
так:
struct sockaddr_in {
__SОСKADDR_COMMON(sin_);
in_port_t sin_port; /* Номер порта */
struct in_addr sin_addr; /* IP-адрес */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SОСKADDR_COMMON_SIZE -
sizeof(in_port_t) - sizeof (struct in_addr)];
};
/* для IPv6. */
struct sockaddr_in6 {
__SОСKADDR_COMMON(sin6_);
in_port_t sin6_port; /* Порт транспортного уровня */
uint32_t sin6_flowinfo; /* Информация потока IPv6 */
struct in6_addr sin6_addr; /* адрес IPv6 */
uint32_t sin6_scope_id; /* IPv6-идентификатор */
};
Поля структуры sockaddr_in означают следующее:
♦ sin_ — набор используемых протоколов. Так как мы используем TCP/IP, данное поле должно содержать значение AF_INET;
♦ sin_port — номер порта;
♦ sin_addr — структура, определяющая адрес узла;
♦ sin_zero — обычно не используется.
Структура struct in_addr, определяющая адрес узла, также описана в файле in.h
:
struct in_addr {
in_addr_t s_addr;
};
Обычно поле s_addr должно принимать значение INADDR_ANY — сейчас поясню почему. Структура sockaddr_in должна быть заполнена ДО вызова функции bind(). Если поле sin_addr.s_addr принимает значение INADDR_ANY, то функция bind() автоматически привяжет к сокету адрес локального компьютера и нам не нужно будет указывать его явно — так наша программа будет универсальной.
Функция bind() возвращает 0 в случае успеха, и -1, если произошла ошибка. Вот небольшой пример использования этой функции:
struct sockaddr_in client;
...
client.sin_family = AF_INET;
client.sin_addr.s_addr = INADDR_ANY;
client.sin_port = 1235;
bind(sock, (struct sockaddr *)&client, sizeof(client));
27.3.3. Установление связи с удаленным компьютером
Устанавливать связь можно как на стороне сервера, так и на стороне клиента. На стороне клиента используется только один вызов — connect(), который «спрашивает» у сервера: «Могу ли я подключиться?», то есть передает запрос на установление соединения. На сервере используются функции:
♦ listen() — ожидание клиента;
♦ accept() — подтверждение запроса клиента на установление соединения.
Сервер должен постоянно прослушивать сокет — ожидать новых клиентов. Как только новый клиент посылает запрос на установление соединения, сервер может либо разрешить ему подключиться (connect), либо запретить (например, если сервер уже обслуживает другого клиента).
Вызов listen() «заставляет» программу-сервер работать в режиме ожидания