Программирование на C++ глазами хакера


Серверные функции - часть 3


Второй параметр — это максимально допустимое число запросов, ожидающих обработки. Допустим, что вы указали здесь значение 3, а вам пришло 5 запросов на соединение от разных клиентов. Только первые три из них встанут в очередь, а остальные получат ошибку WSAECONNREFUSED, поэтому при написании клиента (в части соединения) обязательно должна быть проверка.

При вызове функции listen вы можете получить следующие основные ошибки:

  • WSAEINVAL — функция bind не была вызвана для данного сокета;
  • WSANOTINITIALISED — не загружена библиотека WinSock, т.е. не выполнена функция WSAStartup;
  • WSAENETDOWN — нарушена сетевая подсистема;
  • WSAEISCONN — сокет уже подключен.

Остальные ошибки возникают реже.

Когда клиент попадает в очередь на подключение к серверу, необходимо разрешить соединение с помощью функции accept. Она выглядит следующим образом:

SOCKET accept ( SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen );

Во второй версии есть функция WSAAccept, у которой первые три параметра такие же, как и у функции accept. Функция WSAAccept выглядит следующим образом:

SOCKET WSAAccept ( SOCKET s, struct sockaddr FAR * addr, LPINT addrlen, LPCONDITIONPROC lpfnCondition, DWORD dwCallbackData );

Давайте рассмотрим общие параметры для этих функций :

  • предварительно созданный и запущенный на прослушивание сокет;
  • указатель на структуру типа sockaddr;
  • размер структуры sockaddr, указанной в качестве второго параметра.

После выполнения функции accept второй параметр (addr) будет содержать сведения об IP-адресе клиента, который произвел подключение. Эти данные можно использовать для контроля доступа к серверу по IP-адресу. Но вы должны помнить, что злоумышленнику не составляет труда подделать IP-адрес, поэтому такую защиту нельзя назвать достаточной, но она может усложнить взлом сервера.

Функция accept возвращает указатель на новый сокет, который можно использовать для общения с клиентом. Старая переменная типа SOCKET продолжает слушать порт в ожидании новых соединений, и ее использовать нет смысла. Таким образом, для каждого подключенного клиента будет свой SOCKET, благодаря чему вы сможете работать с любым из них.

Если вы вспомните пример с передачей данных с использованием MFC-объектов (см. разд. 4.5), то там применялся тот же метод. Как только клиент подключался к серверу, мы создавали новый сокет, через который и происходила работа с подключившимся клиентом. Именно этот сокет принимал данные, пришедшие по сети, и мог их отправлять обратно программе на стороне клиента.




Начало  Назад  Вперед



Книжный магазин