
меняется, а файла получателя — меняется. Функция читает указанное число бай тов (параметр count) начиная с заданной позиции (параметр offset). По заверше нии функции указатель *offset ссылается на байт, идущий за последним прочи танным байтом.
Прототип
#include <unistd.h>
int sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
Возвращаемое значение
При успешном завершении функция возвращает общее число скопированных байтов. В случае ошибки возвращается — 1, а в переменную errno записывается код ошибки.
Параметры
out_f |
d |
Дескриптор получателя (указатель текущей позиции файла меняется) |
in_f |
d |
Дескриптор источника (указатель текущей позиции файла не меняется) |
offset |
Указатель на переменную, в которой содержится начальное смещение |
|
count |
Число отправляемых байтов |
|
Возможные ошибки |
||
EBADF |
Входной файл не был открыт для чтения или выходной файл не был открыт |
|
|
|
для записи |
EINVAL |
Дескриптор некорректен или заблокирован |
|
ENOMEM |
Недостаточно памяти для чтения из исходного файла |
|
ЕЮ |
|
Неопределенная ошибка при чтении из исходного файла |
Пример
#include <unistd.h>
struct stat fdstat;
int client = accept(sd,0,0);
int fd = open("filename.gif", O_RDONLY); fstat(fd, &fdstat);
sendfile(client, fd, 0, fdstat.st_size); close(fd);
close(client);
recv()
Функция recv() принимает сообщение от подключенного однорангового ком пьютера, клиента или сервера. Она работает подобно низкоуровневой функции read(), но дополнительно позволяет устанавливать управляющие флаги.
Приложение Б. Сетевые функции |
391 |
Ⱦɚɧɧɚɹ ɜɟɪɫɢɹ ɤɧɢɝɢ ɜɵɩɭɳɟɧɚ ɷɥɟɤɬɪɨɧɧɵɦ ɢɡɞɚɬɟɥɶɫɬɜɨɦ %RRNV VKRS Ɋɚɫɩɪɨɫɬɪɚɧɟɧɢɟ ɩɪɨɞɚɠɚ ɩɟɪɟɡɚɩɢɫɶ ɞɚɧɧɨɣ ɤɧɢɝɢ ɢɥɢ ɟɟ ɱɚɫɬɟɣ ɁȺɉɊȿɓȿɇɕ Ɉ ɜɫɟɯ ɧɚɪɭɲɟɧɢɹɯ ɩɪɨɫɶɛɚ ɫɨɨɛɳɚɬɶ ɩɨ ɚɞɪɟɫɭ piracy@books-shop.com
Прототип
#include <sys/socket.h> #include <resolv.h>
int recv(int sockfd, void *buf, int maxbuf, int options);
Возвращаемое значение
Функция возвращает число прочитанных байтов или 1 в случае ошибки.
Параметры
sockfd |
Дескриптор подключенного сокета |
buf |
Буфер, в который будет помещено поступившее сообщение |
maxbuf |
Размер буфера |
options |
Набор флагов, которые можно объединять с помощью операции побитового сложения: |
*MSG_OOB. Запрашивает получение внеполосных данных, которые не передаются в обычном пото
ке данных. В некоторых протоколах срочные данные помещаются в начало обычной очереди, по этому рассматриваемый флаг не может применяться при работе с такими протоколами;
*MSG_PEEK. Заставляет функцию читать данные, не удаляя их из очереди. Таким образом, при следующей операции чтения будут прочитаны те же самые данные;
*MSG_WAITALL. Запрашивает блокировку программы до тех пор, пока не будет получено все со
общение целиком. Тем не менее функция может завершиться досрочно, если получен сигнал, произошла ошибка или соединение было разорвано противоположной стороной;
*MSG_ERRQUEUE. Запрашивает прием пакета из очереди ошибок сокета. Информация об ошибке
передается в служебном сообщении, тип которого зависит от протокола (для IP сокета нужно ус тановить параметр IP_RECVERR). В теле сообщения находится структура sock_extended_error;
*MSG_NOSIGNAL. Отключает выдачу сигнала SIGPIPE в потоковом сокете при разрыве соединения на противоположной стороне
Возможные ошибки
EBADF |
Указан неверный дескриптор файла |
ENOTCONN |
Сокет не был подключен (см. функции connect() и accept()) |
ENOTSOCK |
Указанный дескриптор связан с файлом, а не с сокетом |
EAGAIN |
Задан режим неблокируемого ввода вывода, а данные недоступны, либо был установ |
|
лен период тайм аута, который превышен до того, как были получены данные |
EINTR |
Сигнал прервал выполнение операции чтения, прежде чем данные стали доступны |
EFAULT |
Указатель буфера чтения ссылается за пределы адресного пространства процесса |
EINVAL |
Передан неверный аргумент |
Пример
/*** Получение сообщения (TCP, UDP) от подключенного узла ***/
int sockfd;
int bytes, bytes_wrote=0;
/*— Создание сокета, подключение к серверу/узлу —*/ if ( (bytes = recv(sockfd, buffer, msg_len, 0)) < 0 )
392 |
Часть V. Приложения |
www.books-shop.com
perror("send");
/*** Получение срочного сообщения (TCP) от подключенного узла ***/
/*** Этот код обычно находится в обработчике сигнала SIGURG ***/
int sockfd;
intbytes, bytes_wrote=0;
/*— Создание сокета, подключение к серверу —*/
if ( (bytes = recv(sockfd, buffer, msg_len, MSG_OOB)) < 0 ) perror("Urgent message");
recvfrom()
Функция recvfrom() принимает сообщение от неподключенного однорангового компьютера (UDP и неструктурированные сокеты). В протоколе Т/ТСР эта функция никогда не используется. Вместо нее вызывается функция accept().
Прототип
linclude <sys/socket.h> linclude <resolv.h>
int recvfromfint sockfd, void* buf, int buf_len, int options, struct sockaddr *addr, int *addr_len);
Возвращаемое значение
При успешном завершении возвращается число прочитанных байтов. В случае ошибки возвращается — 1, а в переменную errno записывается код ошибки.
Параметры
sockfd |
Дескриптор сокета |
|
buf |
Буфер для приема сообщения |
|
buf _lеп |
Максимальный размер буфера (сообщение усекается, если буфер слишком мал) |
|
options |
Параметры управления каналом (такие же, как и в функции recv()) |
|
addr |
Адрес и порт отправителя |
|
addr_len |
Максимальный размер адресной структуры (адрес усекается, если буфер слишком |
|
|
|
мал); по завершении функции в этом параметре будет содержаться реальная длина |
|
|
адреса |
Возможные ошибки
(Те же, что и в функции recv())
Пример
struct sockaddr_in addr;
int addr_len=sizeof(addr), bytes_read; char buf[l024];
Приложение Б. Сетевые функции |
393 |
www.books-shop.com
int |
sockfd = socket (PF_INET, SOCK_DGRAM, 0); |
/* — |
привязка к конкретному порту —*/ |
bytes_read = recvfrom(sockfd, buf, sizeof(buf), 0, &addr, |
|
|
&addr_len); |
if(bytes_read<0) |
|
|
perror("recvfrom failed"); |
recvmsg()
Функция recvmsg() принимает сразу несколько сообщений от одного источни ка. Она может использоваться с сокетами типа SOCK_DGRAM (аналогично тому, как это происходит в случае функции sendmsg()).
Прототип
#include <sys/socket.h> #include <resolv.h> #include <sys/uio.h>
int recvmsg(int sockfd, struct msghdr *msg, unsigned int options);
Возвращаемое значение
При успешном завершении возвращается общее число полученных байтов, в противномслучаевозвращается—1.
Параметры
sockfd |
Дескриптор сокета |
msg |
Буфер для принимаемых данных |
options |
Параметры управления каналом (такие же, как и в функции recv( )) |
Возможные ошибки
(Те же, что и в функции recv())
Пример
char buffer[MSGS][1000]; struct sockaddr_in addr; struct iovec io[MSGS]; struct msghdr msg;
bzero(&addr, sizeof(addr)); msg.msg_name = &addr; msg.msg_namelen = sizeof (addr); for ( i = 0; i < MSGS; i++ )
{
io[i].iov_base = buffer(i);
io[i].iov_len = sizeof (buffer[i]);
}
394 |
Часть V. Приложения |
www.books-shop.com
msg.msg_iov = io; msg.msg_iovlen = MSGS;
if ( (bytes = recvmsg(sd, &msg, 0)) < 0 ) perror("recvmsg");
Разрыв соединения
После того как программа закончила сеанс связи с внешним узлом, она долж на закрыть соединение. Ниже описывается функция, ответственная за разрыв со единения.
shutdown()
Функция shutdown() закрывает указанные части канала передачи данных. Со единение, устанавливаемое посредством сокета, по умолчанию является двуна правленным. Если нужно сделать его доступным только для чтения или только для записи, то следует с помощью функции shutdown() закрыть один из концов канала.
Прототип
#include <sys/socket.h>
int shutdown(int sockfd, int how);
Возвращаемое значение
Если все прошло успешно, возвращается 0. В случае ошибки ее код можно найти в переменной еrrno.
Параметры
sockfd |
Дескриптор сокета |
how |
флаг, указывающий на то, какую часть канала следует закрыть: |
*SHUT_RD (0) — сделать канал доступным только для записи;
*SHUT _WR(1) — сделать канал доступным только для чтения;
*SHUT_RDWR (2) — закрыть обе половины канала (эквивалентно вызову функции close()). Выполнять эти действия можно только в отношении подключенных сокетов
Возможные ошибки
EBADF |
Указан неверный дескриптор сокета |
ENOTSOCK |
Указанный дескриптор связан с файлом, а не с сокетом |
ENOTCONN |
Указанный сокет не является подключенным |
Приложение Б. Сетевые функции |
395 |
www.books-shop.com
Пример
int sockfd;
struct sockaddr_in addr;
sockfd = socket(PF_INET, SOCK_STREAM, 0); bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET;
addr.sin_port = htons(DEST_PORT); inet_aton (DEST_ADDR, &addr. sin_addr); connect(sockfd, &addr, sizeof(addr)); if ( shutdown(sockfd, SHUT_WR) != 0 )
PANIC("Can't make socket input only");
Преобразование данных в сети
Работая с данными по сети, необходимо учитывать порядок следования бай тов, преобразовывать адреса и т.д. В библиотеку Socket API входит достаточно большое число функций, помогающих получать информацию в нужном формате. Ниже описаны функции, которые использовались в книге.
htons(), htonl()
Функции htons() и htonl() преобразуют двоичные данные из серверного по рядка следования байтов в сетевой. В случае процессора с прямым порядком хра нения данных происходит перестановка байтов. Если в компьютере установлен процессор с обратным порядком байтов, функция возвращает свой аргумент в неизменном виде.
Прототип
#include |
<netinet/in.h> |
unsigned |
short int htons(unsigned short int host_short); |
unsigned |
long int htonl(unsigned long int host_long); |
Возвращаемое значение
Преобразованный аргумент (16 или 32 разрядный).
Параметры
host_short |
16 разрядное значение с серверным порядком следования байтов |
host_long |
32 разрядное значение с серверным порядком следования байтов |
Возможные ошибки
(отсутствуют)
396 Часть V. Приложения
www.books-shop.com
Пример
/*** Связываем сокет с портом 1023 ***/
struct sockaddr_in addr; addr.sin_port = htons(1023);
/*** Связываем сокет с адресом 128.1.32.10 ***/
struct sockaddr_in addr; addr.sin_addr.s_addr = htonl(Ox8001200A);
ntohs(), ntohl()
Функции ntohs() и ntohl() преобразуют двоичные данные из сетевого порядка следования байтов в серверный.
Прототип
#include <netinet/in.h>
unsigned short int ntohs(unsigned short int network_short); unsigned long int ntohl(unsigned long int network_long);
Возвращаемое значение
Преобразованный аргумент (16 или 32 разрядный).
Параметры |
|
network_short |
16 разрядное значение с сетевым порядком следования байтов |
network_long |
32 разрядное значение с сетевым порядком следования байтов |
Возможные ошибки
(отсутствуют)
Пример
struct sockaddr_in addr;
int client, addrlen=sizeof(addr);
client = accept(sockfd, &addr, &addrlen); if ( client > 0 )
printf("Connected %lX:%d\n", ntohl(addr.sin_addr), ntohs(addr.sin_port));
inet_addr()
Функция inet_addr() считается устаревшей. Она преобразует IP адрес из то чечной нотации в двоичную форму с сетевым порядком следования байтов. В случае неудачи возвращается значение — 1, которое также является корректным IP адресом (255.255.255.255). Лучше пользоваться функцией inet_aton().
Приложение Б. Сетевые функции |
397 |
www.books-shop.com
Прототип
#include<netinet/in.h>
unsigned long int inet_addr(const char *ip_address);
Возвращаемое значение
He нуль |
Если все прошло успешно, возвращается преобразованный IP адрес |
INADDR_NONE ( 1) |
Аргумент является неправильным. (Это ошибка функции. Она не возвращает от |
|
рицательное значение, а значение 255.255.255.255 обозначает обычный ши |
|
роковещательный адрес.) |
Параметры |
|
ip_address |
IP адрес в традиционной, точечной нотации (например, 128.187.34.2) |
Возможные ошибки
(переменная errno не устанавливается)
Пример
if ( (addr.sin_addr.s_addr = inet_addr("182.187.34.2")) == 1 ) perror("Couldn't convert address");
inet_aton()
Функция inet_aton() преобразует IP адрес из точечной нотации в двоичную форму с сетевым порядком следования байтов. Она заменяет функцию inet_addr().
Прототип
#include <netinet/in.h>
int inet_aton(const char *ip_addr, struct in_addr *addr);
Возвращаемое значение
Если все прошло успешно, возвращается ненулевое значение. В противном случае возвращается нуль.
Параметры |
|
ip_addr |
ASCII строка с IP адресом (например, 187.34.2.1) |
addr |
Переменная, куда записывается адрес; обычно заполняется поле sin_addr |
|
структуры sockaddr_in |
398 Часть V. Приложения
www.books-shop.com
Возможные ошибки
(переменная errno не устанавливается)
Пример
struct sockaddr_in addr;
if ( inet_aton("187.43.32.1", &addr.sin_addr) == 0 perror("inet_aton() failed");
inet_ntoa()
Функция inet_ntoa() преобразует IP адрес из двоичной формы с сетевым по рядком следования байтов в точечную нотацию.
Прототип
iinclude <netinet/in.h>
int inet_ntoa(struct in_addr *addr);
Возвращаемое значение
Функция возвращает строку с адресом. |
|
Параметры |
|
addr |
Двоичный адрес (обычно это адресное поле структуры sockaddr_in) |
Возможные ошибки |
|
(переменная errno не устанавливается) |
|
Пример |
|
clientfd = accept(serverfd, &addr, &addr_size); |
|
if ( clientfd > 0 ) |
|
printf("Connected %s:%d\n", inet_ntoa(addr.sin_addr), |
|
|
ntohs(addr.sin_port)); |
inet_pton()
Функция inet_pton() преобразует адрес IPv4 или IPv6 из символьного пред ставления в двоичную форму с сетевым порядком следования байтов.
Прототип
Iinclude <arpa/inet.h>
int inet_pton(int domain, const char* prsnt, void* addr);
Приложение Б. Сетевые функции |
399 |
www.books-shop.com
Возвращаемое значение
В случае успешного завершения возвращается ненулевое значение. Если воз никает ошибка, возвращается нуль.
Параметры
domain |
Семейство адресов (AF_INET или AF_INET6) |
|
prsnt |
ASCII строка с IP адресом (например, 187.34.2.1 или |
FFFF:8090:АОЗ:3245) |
addr |
Переменная, куда записывается адрес; обычно заполняется поле sin_addr структуры |
|
|
sockaddr_in или поле sin6_addr структуры sockaddr_in6 |
Возможные ошибки
(переменная errno не устанавливается)
Пример
struct sockaddr_in addr;
if ( inet_pton(AF_INET, "187.43.32.1", &addr.sin_addr) == 0 ) perror("inet pton() failed");
inet_ntop()
Функция inet_pton() преобразует адрес из двоичного представления с сетевым порядком следования байтов в символьную форму. Функция поддерживает се мейства адресов AF_INET и AF_INET6.
Прототип
#include <arpa/inet.h>
int inet_ntop(int domain, struct in_addr *addr, char* str, int len);
Возвращаемое значение |
|
Функция возвращает строку str. |
|
Параметры |
|
domain |
Семейство адресов (AF_INET или AF_INET6) |
addr |
Двоичный адрес (обычно это адресное поле структуры sockaddr in) |
str |
Буфер для строки адреса |
len |
Размер буфера |
400 |
Часть V. Приложения |
www.books-shop.com