
Возможные ошибки
(переменная errno не устанавливается)
Пример
char str[100];
clientfd = accept(serverfd, &addr, &addr_size); if ( clientfd > 0 )
printf("Connected %s:%d\n",
inet_ntop(AF_INET, addr.sin_addr, str, sizeof(str)), ntohs(addr.sin_port));
Работа с сетевыми адресами
В библиотеку Socket API входят также функции, позволяющие получить дос туп к различным службам имен или самостоятельно выполняющие преобразова ния имен.
getpeername()
Функция getpeername() определяет адрес или имя компьютера, подключенного к противоположному концу сокета с дескриптором sockfd. Результат помещается в буфер addr. Параметр addr_len определяет размер адресного буфера. Это та же самая информация, которую можно получить с помощью функции accept().
Прототип
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addr_len);
Возвращаемое значение
Вслучае успешного завершения возвращается нуль. Если произошла ошибка,
еекод помещается в переменную errno.
Параметры
sockfd |
Дескриптор подключенного сокета |
|
addr |
Буфер, в который помещается адресная структура |
|
addr_len |
Размер буфера; этот параметр передается по ссылке, так как функция записывает |
|
|
сюда реальный размер адреса |
|
Возможные ошибки |
|
|
EBADF |
Указан неверный дескриптор |
|
Приложение Б. Сетевые функции |
401 |
Ⱦɚɧɧɚɹ ɜɟɪɫɢɹ ɤɧɢɝɢ ɜɵɩɭɳɟɧɚ ɷɥɟɤɬɪɨɧɧɵɦ ɢɡɞɚɬɟɥɶɫɬɜɨɦ %RRNV VKRS Ɋɚɫɩɪɨɫɬɪɚɧɟɧɢɟ ɩɪɨɞɚɠɚ ɩɟɪɟɡɚɩɢɫɶ ɞɚɧɧɨɣ ɤɧɢɝɢ ɢɥɢ ɟɟ ɱɚɫɬɟɣ ɁȺɉɊȿɓȿɇɕ Ɉ ɜɫɟɯ ɧɚɪɭɲɟɧɢɹɯ ɩɪɨɫɶɛɚ ɫɨɨɛɳɚɬɶ ɩɨ ɚɞɪɟɫɭ piracy@books-shop.com
ENOTSOCK |
Указанный дескриптор относится к файлу, а не к сокету |
ЕNOТСОNN |
Сокет не подключен |
ENOBUFS |
В системе недостаточно ресурсов для выполнения операции |
EFAULT |
Указатель addr ссылается за пределы адресного пространства процесса |
Пример
struct sockaddr_in addr; int addr_len = sizeof(addr);
if { getpeername(client, &addr, &addr_len) != 0 ) perror("getpeername() failed");
printf("Peer: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
gethostname()
Функция gethostname() возвращает имя локального узла. Результат помещается в буфер name, размер которого определяется параметром len.
Прототип
#include <unistd.h>
int gethostname(char *name, size_t len);
Возвращаемое значение
В случае успешного завершения возвращается нуль. Если произошла ошибка,
еекод помещается в переменную errno.
Параметры
name |
Буфер, в который записывается имя узла |
len |
Размер буфера |
Возможные ошибки |
|
EINVAL |
Параметр len является отрицательным либо, если функция выполняется на платформе |
|
Linux/i386,значение параметра len оказалось меньше, чем реальный размер имени |
EFAULT |
Параметр name содержит неправильный адрес |
Пример
char name[50];
if ( gethostname(name, sizeof(name)) != 0 perror("gethostname() failed");
printf("My host is: %s\n", name);
402 Часть V. Приложения
www.books-shop.com
gethostbyname()
Функция gethostbyname() ищет имя узла в базе данных DNS сервера и преоб разует его в IP адрес. Функции может передаваться как имя, так и сам адрес. Во втором случае поиск не осуществляется; вместо этого адрес возвращается в полях h name и h addr list[0] структуры hostent.
Прототип
#include <netdb.h>
struct hostent *gethostbyname(const char *name);
Возвращаемое значение
Функция возвращает указатель на структуру hostent. В случае неудачи возвра щается NULL. В структуре содержится список всех имен и адресов, связанных с данным узлом. Макроконстанта h_addr существует для совместимости со старыми приложениями.
#define h_addr h_addr_list[0] |
|
|
||||
struct hostent { |
|
|
|
|
|
|
char |
*h_name; |
|
/* официальное имя узла */ |
|
||
char |
**h_aliases; |
/* список псевдонимов */ |
|
|||
int |
h_addrtype; |
/* тип адреса */ |
|
|||
int |
h_length; |
|
/* |
длина |
адреса */ |
|
char **h_addr_list; |
/* |
список |
адресов; нулевой главный |
*/ |
||
}; |
|
|
|
|
|
|
Параметры |
|
|
|
|
|
|
name |
|
|
Имя узла для поиска или IP адрес |
|
||
Возможные ошибки |
|
|
||||
ENOTFOUND |
|
Указанный узел не найден |
|
|||
NO_ADDRESS, NO_DATA |
Указанное имя является корректным, но с ним не связан IP адрес |
|||||
NO_RECOVERY |
|
Произошла фатальная ошибка сервера имен |
|
|||
EAGAIN |
|
|
Произошла временная ошибка сервера имен, повторите попытку позднее |
|||
Пример |
|
|
|
|
|
|
int i; |
|
|
|
|
|
|
struct hostent *host; |
|
|
|
|
||
host = gethostbyname("sunsite.unc.edu"); |
|
|||||
if ( host |
!= NULL |
) |
|
|
|
|
{ |
|
|
|
|
|
|
printf("Official name: %s\n", host >h_name); |
|
|||||
for ( i = 0; host >h_aliases[i] != 0; i++) |
|
|||||
|
printf(" |
alias[%d]: %s\n", i+1, host >h_aliases[i]); |
||||
Приложение Б. Сетевые функции |
403 |
www.books-shop.com
printf("Address type=%d\n", host >h_addrtype); for ( i = 0; i < host >h_length; i++)
printf("Addr[%d]: %s\n", i+1, inet_ntoa(host >h_addr_list[i]));
}
else
perror("sunsite.unc.edu");
getprotobyname()
Функция getprotobyname() просматривает файл /etc/protocols в поиске прото кола с указанным именем. Эту функцию можно использовать для трансляции имен протоколов, таких как HTTP, FTP или Telnet, в соответствующие им номе ра портов.
Прототип
#include<netdb.h>
struct protoent *getprotobyname(const char* pname);
Возвращаемое значение
В случае успешного завершения функция возвращает указатель на структуру protoent. В противном случае возвращается NULL.
struct protoent { |
|
|
char |
*p_name; |
/* официальное имя протокола */ |
char |
**p_aliases; /* список псевдонимов */ |
|
int |
p_proto; |
/* номер порта */ |
};
Параметры
pname Имя протокола; это может быть любое известное имя протокола или псевдоним
Возможные ошибки
(переменная errno не устанавливается)
Пример
#include <netdb.h>
int i;
struct protoent *proto = getprotobyname("http"); if ( proto != NULL )
{
printf("Official name: %s\n", proto >name); printf("Port!: %d\n", proto >p proto);
for ( i = 0; proto >p aliases[I] != 0;
404 |
Часть V. Приложения |
www.books-shop.com
printf("Alias[%d]: %s\n", i+1, proto >p_aliases[i]);
else perror("http");
Управление сокетами
Когда сокет открыт, можно менять самые разные его параметры. Для этой це ли предназначены описанные ниже функции.
setsockopt()
Функция setsockopt() изменяет поведение сокета. У каждого параметра сокета есть значение (некоторые доступны только для чтения). Полный список парамет ров приведен в приложении А, "Информационные таблицы".
Прототип
#include <sys/types.h> #include <sys/socket.h>
int setsockopt(int sd, int level, int optname,
const void *optval, socklen_t optlen);
Возвращаемое значение
Вслучае успешного завершения возвращается нуль. Если произошла ошибка,
еекод помещается в переменную errno.
Параметры |
|
|
sd |
Дескриптор сокета |
|
level |
Уровень параметра сокета (SOL_SOCKET, SOL_IP, SOL_IPV6, SOL_TCP) |
|
optname |
Имя параметра сокета |
|
optval |
Указатель на новое значение параметра сокета |
|
optlen |
Длина параметра сокета в байтах |
|
Возможные ошибки |
|
|
EBADF |
Указан неверный дескриптор сокета |
|
ENOTSOCK |
Указанный дескриптор относится к файлу, а не к сокету |
|
ENOPROTOOPT |
Указанный параметр сокета не известен на данном уровне |
|
EFAULT |
Указатель optval ссылается за пределы адресного пространства процесса |
|
Примеры |
|
|
const int TTL=128; |
|
|
/*— Задание предельного числа переходов равным 128 —*/ |
|
|
Приложение Б. Сетевые функции |
405 |
www.books-shop.com
if ( setsockopt(sd, SOL_IP, SO_TTL, &TTL, sizeof(TTL)) != 0 ) perror("setsockopt() failed");
getsockopt()
Функция getsockopt() возвращает значение указанного параметра сокета.
Прототип
#include <sys/types.h> iinclude <sys/socket.h>
int getsockopt(int sd, int level, int optname, void *optval, socklen_t *optlen);
Возвращаемое значение
Вслучае успешного завершения возвращается нуль. Если произошла ошибка,
еекод помещается в переменную errno.
Параметры
sd |
Дескриптор сокета |
level |
Уровень параметра сокета (SOL_SOCKET, SOL_IP, SOL_IPV6, SOL_TCP) |
optname |
Имя параметра сокета |
optval |
Буфер для значения параметра сокета |
optlen |
Длина буфера; это значение передается по ссылке, так как функция записывает |
|
сюда реальную длину буфера |
Возможные ошибки |
|
EBADF |
Указан неверный дескриптор сокета |
ENOTSOCK |
Указанный дескриптор относится к файлу, а не к сокету |
ENOPROTOOPT |
Указанный параметр сокета не известен на данном уровне |
EFAULT |
Указатель optval или optlen ссылается за пределы адресного пространства |
|
процесса |
Пример
int error, size = sizeof(error);
if ( getsockopt(sd, SOL_SOCKET, SO_ERROR, &error, &size)) != 0 ) perror("getsockopt() failed");
printf("socket error=%d\n", error);
406 |
Часть V. Приложения |
www.books-shop.com
API функции ядра |
Приложение |
|
В
В этом приложении... |
|
Задания |
408 |
Потоки |
415 |
Блокировка |
418 |
Сигналы |
421 |
Работа с файлами |
424 |
www.books-shop.com
В этом приложении приведена справочная информация, касающаяся библио течных функций ядра и системных вызовов, которые не связаны с сокетами на прямую, но обычно используются совместно с ними.
Задания
К заданиям относятся процессы и потоки. Функции библиотеки Pthreads, предназначенные для работы с потоками, будут рассматриваться в следующем разделе. Здесь же речь пойдет о функциях, применяемых к процессам.
fork()
Функция fork() создает новый процесс (независимое задание). Дочерний про цесс выполняет тот же программный файл, что и его предок. Необходимо преду смотреть ветвление алгоритма в программе, иначе произойдет дублирование ис полняемого кода.
Прототип
#include <unistd.h> pid_t fork(void);
Возвращаемое значение
0 Текущее задание является дочерним >0 Текущее задание является родительским
<0 Дочернее задание не удалось создать; код ошибки содержится в переменной errno
Параметры
(отсутствуют)
Возможные ошибки
EAGAIN |
Недостаточно памяти для копирования таблицы страниц родительского задания и создания |
|
информационной структуры дочернего задания |
ENOMEM |
Недостаточно памяти для создания необходимых структур ядра |
Пример
int PID;
if ( (PID = fork()) == 0 )
{/*— ПОТОМОК —*/
/*** выполняем соответствующие действия ***/
exit(status);
}
else if ( PID > 0 )
{/*— ПРЕДОК —*/
408 |
Часть V. Приложения |
www.books-shop.com
int status;
/*** выполняем соответствующие действия ***/
wait(Sstatus); /* эта функция может вызываться
в обработчике сигнала SIGCHLD */
}
else /*— ОШИБКА —*/ perror("fork() failed");
_clone()
Это низкоуровневый системный вызов, предназначенный для создания зада ний. Можно непосредственно указывать, какие данные будут совместно исполь зоваться родительским и дочерним заданиями. Эта функция предназначена для настоящих профессионалов, так как любая ошибка может привести к непредска зуемой работе программы.
Прототип
iinclude <sched.h>
int _clone(int (*fn)(void* arg), void* stacktop, int flags, void* arg);
Возвращаемое значение
Функция возвращает идентификатор созданного задания. В случае неудачи код ошибки записывается в переменную errno.
Параметры
f n |
Указатель на функцию потока, принимающую аргумент типа void*; когда она завер |
|
шается, операционная система останавливает поток |
stacktop |
Указатель на вершину стека дочернего задания (самый старший адрес блока данных); |
|
этот стек имеет фиксированный размер и не может увеличиваться подобно стеку |
|
обычного задания |
flags |
Набор флагов, определяющих, какие области памяти совместно используются и какой |
|
сигнал посылать в случае завершения дочернего задания. Поддерживаются все виды |
|
сигналов, и при завершении задания операционная система сгенерирует любой ука |
|
занныйсигнал. |
|
Следующие флаги определяют, какие из областей памяти задания будут доступны для |
|
совместного использования: |
*CLONE_VM. Совместное использование области данных между заданиями. Если флаг указан,
будут доступны все статические и предварительно инициализированные переменные, а так же блоки, выделенные в куче. В противном случае в дочернем задании будет создана копия области данных;
*CLONE_FS. Совместное использование информации о файловой системе: о текущем катало ге, корневом каталоге и стандартном режиме доступа к файлам (значение umask). Если флаг не указан, задания будут вести себя независимо друг от друга;
*CLONE FILES. Совместное использование открытых файлов. Когда в одном задании пере мещается указатель текущей позиции файла, в другом задании отразится это изменение, и если закрыть файл в одном задании, то и в другом он станет недоступным. Если флаг не
Приложение В. API функции ядра |
409 |
www.books-shop.com
указан, в дочернем задании создаются новые ссылки на открытые индексные дескрипторы;
*CLONE SIGHAND. Совместное использование таблиц сигналов. Каждое задание может запре тить обработку того или иного сигнала с помощью функции sigprocmask( ) , и это не отра зится на других заданиях. Если флаг не указан, в дочернем задании создается копия табли цы сигналов;
*CLONE_PID.Совместное использование идентификатора процесса. Применятьданный флаг
следует осторожно, так как он не всегда поддерживается (как это имеет место в случае биб лиотеки Pthreads). Если флаг не указан, в дочернем задании создается новый идентификатор процесса
arg |
Указатель на блок данных, передаваемых в качестве параметра потоковой функции fп. |
|
Эти данные должны находиться в совместно используемой области памяти |
Возможные ошибки |
|
EAGAIN |
Недостаточно памяти для копирования таблицы страниц родительского задания и соз |
|
дания информационной структуры дочернего задания |
ENOMEM |
Недостаточно памяти для создания необходимых структур ядра |
Пример
fdefine STACKSIZE 1024
void Child(void *arg)
{
/* код потомка */
exit(O);
}
int main (void)
{int cchild;
char *stack = malloc( STACKSIZE);
if ( (cchild = _clone(&Child, stack+STACKSIZE 1,
SIGCHLD, 0)) == 0 )
{ /*** секция дочернего задания — недоступна ***/
}
else if ( cchild > 0 ) wait();
else
perror("Can't clone task");
}
exec()
Функции данного семейства предназначены для запуска внешних программ (это могут быть либо двоичные исполняемые файлы, либо сценарии, начинающиеся со строки вида #! <интерпретатор> [аргументы]). Функция замещает контекст те кущего выполняемого задания контекстом внешней программы, которая сохраняет идентификатор запустившего ее процесса и список открытых файлов.
410 |
Часть V. Приложения |
www.books-shop.com