Составители:
Рубрика:
следние два параметра являются необязательными. Если в программе не требуется знать адрес клиента,
задайте эти параметры равными нулю.
Необходимо убедиться, что размер буфера адреса достаточен для размещения в нем полученной
адресной структуры. Беспокоиться о повреждении данных из-за переполнения буфера не стоит: функция
задействует ровно столько байтов, сколько указано в третьем
параметре. Параметр addr size передается
по ссылке, поэтому программа может легко узнать реальный размер полученной структуры (листинг
6.4).
Листинг 6. Пример функции accept ().
/***************************************************************/
/*** Пример функции accept(): ожидание и принятие запросов ***/
/*** на подключение от клиентов ***/
/***************************************************************/
int sd;
struct sockaddr in addr;
/*** Создание сокета, привязка его к порту и
перевод в режим прослушивания ***/
for (;;) /* цикл повторяется бесконечно */
{ int clientsd; /* новый дескриптор сокета */
int size = sizeof(addr); /* вычисление размера структуры */
clientsd = accept(sd, saddr, &size); /* ожидание подключения */
if ( clientsd > 0 ) /* ошибок нет */
{
/*** взаимодействие с клиентом ***/
close(clientsd); /* очистка и отключение */
}
else /* произошла ошибка */
perror ("Accept");
Взаимодействие с клиентом
Обратите внимание на то, что в приведенном выше фрагменте программы закрывался дескриптор
clientsd, который отличается от основного дескриптора сокета. Это очень важный момент, поскольку для
каждого соединения создается отдельный дескриптор. Если забыть их закрыть, лимит дескрипторов мо-
жет со временем исчерпаться.
Повторное использование адресной структуры
В функции accept () можно использовать адресную структуру, инициализированную еще при вызове
функции bind(). По завершении функции bind() хранящаяся в этой структуре информация больше не
нужна серверу.
Помните, что большинство полей структуры имеет сетевой порядок следования байтов. Извлечь адрес и но-
мер порта из переменной addr можно с помощью функций преобразования (Листинг 7).
Листинг 7.Пример функции accept () с регистрацией подключений.
/****************************************************************/
/*** Расширенный пример функции accept(): информация ***/
/*** о каждом новом подключении отображается на экране ***/
/****************************************************************/
/*** (Внутри цикла) ***/
client = accept(sd, &addr, &size);
if ( client > 0 )
{
if ( addr.sin_faaily == AF_INET)
printf("Connection[%s]: %s:%d\n", /* регистрация */
ctime(tiine(0)), /* метка времени */
ntoa(addr.sin_addr), ntohs(addr.sin_port));
/*--- взаимодействие с клиентом ---*/
Если в процессе выполнения функции accept () происходит ошибка, функция возвращает отрица-
тельное значение. В противном случае создается новый дескриптор сокета. Ниже перечислены коды
возможных ошибок.
•EBADF.
Указан неверный дескриптор сокета.
•EOPNOTSOPP. При вызове функции accept () сокет должен иметь тип SOCK_STREAM.
•EAGAIN. Сокет находится в режиме неблокируемого ввода-вывода, а очередь ожидания пуста.
Функция accept () блокирует работу программы, если не включен данный режим.
Настало время вернуться к эхо-серверу, который возвращает клиенту полученное сообщение до
тех пор, пока не поступит команда
bye (Листинг 8).
следние два параметра являются необязательными. Если в программе не требуется знать адрес клиента, задайте эти параметры равными нулю. Необходимо убедиться, что размер буфера адреса достаточен для размещения в нем полученной адресной структуры. Беспокоиться о повреждении данных из-за переполнения буфера не стоит: функция задействует ровно столько байтов, сколько указано в третьем параметре. Параметр addr size передается по ссылке, поэтому программа может легко узнать реальный размер полученной структуры (листинг 6.4). Листинг 6. Пример функции accept (). /***************************************************************/ /*** Пример функции accept(): ожидание и принятие запросов ***/ /*** на подключение от клиентов ***/ /***************************************************************/ int sd; struct sockaddr in addr; /*** Создание сокета, привязка его к порту и перевод в режим прослушивания ***/ for (;;) /* цикл повторяется бесконечно */ { int clientsd; /* новый дескриптор сокета */ int size = sizeof(addr); /* вычисление размера структуры */ clientsd = accept(sd, saddr, &size); /* ожидание подключения */ if ( clientsd > 0 ) /* ошибок нет */ { /*** взаимодействие с клиентом ***/ close(clientsd); /* очистка и отключение */ } else /* произошла ошибка */ perror ("Accept"); Взаимодействие с клиентом Обратите внимание на то, что в приведенном выше фрагменте программы закрывался дескриптор clientsd, который отличается от основного дескриптора сокета. Это очень важный момент, поскольку для каждого соединения создается отдельный дескриптор. Если забыть их закрыть, лимит дескрипторов мо- жет со временем исчерпаться. Повторное использование адресной структуры В функции accept () можно использовать адресную структуру, инициализированную еще при вызове функции bind(). По завершении функции bind() хранящаяся в этой структуре информация больше не нужна серверу. Помните, что большинство полей структуры имеет сетевой порядок следования байтов. Извлечь адрес и но- мер порта из переменной addr можно с помощью функций преобразования (Листинг 7). Листинг 7.Пример функции accept () с регистрацией подключений. /****************************************************************/ /*** Расширенный пример функции accept(): информация ***/ /*** о каждом новом подключении отображается на экране ***/ /****************************************************************/ /*** (Внутри цикла) ***/ client = accept(sd, &addr, &size); if ( client > 0 ) { if ( addr.sin_faaily == AF_INET) printf("Connection[%s]: %s:%d\n", /* регистрация */ ctime(tiine(0)), /* метка времени */ ntoa(addr.sin_addr), ntohs(addr.sin_port)); /*--- взаимодействие с клиентом ---*/ Если в процессе выполнения функции accept () происходит ошибка, функция возвращает отрица- тельное значение. В противном случае создается новый дескриптор сокета. Ниже перечислены коды возможных ошибок. •EBADF. Указан неверный дескриптор сокета. •EOPNOTSOPP. При вызове функции accept () сокет должен иметь тип SOCK_STREAM. •EAGAIN. Сокет находится в режиме неблокируемого ввода-вывода, а очередь ожидания пуста. Функция accept () блокирует работу программы, если не включен данный режим. Настало время вернуться к эхо-серверу, который возвращает клиенту полученное сообщение до тех пор, пока не поступит команда bye (Листинг 8).