Все эти вызовы используют в качестве первого аргумента дескриптор сокета, через который производится обмен данными. Аргумент msg
содержит сообщение длиной len
, которое должно быть передано по адресу toaddr
, длина которого составляет tolen
байтов. Для функции buf
представляет собой буфер, в который копируются полученные данные.
Параметр flags
может принимать следующие значения:
MSG_OOB | Передать или принять экстренные данные вместо обычных |
MSG_PEEK | Просмотреть данные, не удаляя их из системного буфера (последующие операции чтения получат те же данные) |
Пример использования сокетов
В заключение приведем пример использования сокетов для организации межпроцессного взаимодействия. Поскольку в данном разделе не затрагиваются сетевые вопросы, то и сокеты, которые будут использованы в примере, принадлежат домену UNIX. Как и в предыдущих примерах, функциональность нашей распределенной системы не отличается разнообразием: клиент посылает серверу сообщение "Здравствуй, Мир!", а сервер отправляет его обратно клиенту, который после получения выводит сообщение на экран.
В примере использованы сокеты датаграмм, которые в домене UNIX практически не отличаются от сокетов потока. В качестве адреса сервера предлагается имя файла ./echo.server (мы полагаем, что в системе запущен только один сервер из данного каталога). Предполагается, что клиенты заранее знают этот адрес. Сервер связывает созданный сокет с этим локальным адресом и таким образом регистрируется в системе. Начиная с этого момента он готов к получению и обработке сообщений. Сервер начинает бесконечный цикл, ожидая сообщений от клиентов, блокируясь на вызове
#include
#include
#include
#define MAXBUF 256 char
buf[MAXBUF];
main {
struct sockaddr_un serv_addr, clnt_addr;
int sockfd;
int saddrlen, caddrlen, max caddrlen, n;
/* Создадим сокет */
if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0} {
printf("Невозможно создать сокет\n");
exit(1);
}
/* Свяжем сокет с известным локальным адресом. Поскольку адрес
в домене UNIX представляет собой имя файла, который будет
создан системным вызовом bind(2), сначала удалим файл с этим
именем в случае, если он сохранился от предыдущего запуска
сервера */
unlink("./echo_server");
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, "./echo.server");
saddrlen =
sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
if (bind(sockfd, (struct sockaddr*)&serv_addr,
saddrlen) < 0) {
printf("Ошибка связывания сокета с адресом\n");
exit(1);
}
/* Теперь запустим бесконечный цикл чтения сообщений от
клиентов и отправления их обратно */
max_caddrlen = sizeof(clnt_addr);
for(;;) {
caddrlen = max_caddrlen;
n = recvfrom(sockfd, buf, MAXBUF, 0,
(struct sockaddr*)&clnt_addr, &caddrlen);
if (n < 0) {
printf("Ошибка приема\n");
exit(1);
}
/* Благодаря вызову recvfrom(2), мы знаем адрес клиента,
от которого получено сообщение. Используем этот адрес
для передачи сообщения обратно отправителю */
if (sendto(sockfd, buf, n, 0,
(struct sockaddr*)&clnt_addr, caddrlen) != n) {
printf("Ошибка передачи\n");
exit(1);
}
}
}