![]() |
Модераторы: feodorv |
![]() ![]() ![]() |
|
MnxVol |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 15.1.2008 Репутация: нет Всего: нет |
Здравствуйте! Подскажите пожалуйста, в чем может быть проблема. Есть задание написать серверное приложение на Си, которое будет выступать в качестве сервера N2H2 для маршрутизатора Cisco. Смысл данного сервера - ограничение доступа пользователей к ресурсам, указанным в файле banners.txt. Есть рабочее приложение на perl (переработанное из неработающего приложения вот тут: http://www.opennet.ru/base/cisco/cisco_banner.txt.html). Нужно было написать то же самое, но на Си. В итоге программа была написана, и программа работает, но до определенного момента, пока не заканчиваются файловые дескрипторы в моем debian (так как для завершения сокета в цикле используется функция shutdown, вместо close - при использовании close cisco не дает открыть никакую страницу, интернет попросту висит). Извиняюсь за много букв, но я постарался как можно кратко объяснить суть проблемы. спасибо за посильную помощь. Внизу привожу код на Си.
В файле - код на perl. Это сообщение отредактировал(а) Олег2005 - 22.10.2012, 14:23 |
|||
|
||||
boostcoder |
|
|||
![]() pattern`щик ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 5458 Регистрация: 1.4.2010 Репутация: 13 Всего: 110 |
||||
|
||||
feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 10 Всего: 45 |
А я так понял, что сокет вообще не нужно закрывать, ни с помощью shutdown, ни с помощью close.
Просто нужно висеть на этом сокете и ждать прихода пакета. На каждый пришедший пакет слать ответ:
-------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
MnxVol |
|
||||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 15.1.2008 Репутация: нет Всего: нет |
пробовал.
если не использую ни shutdown ни close - сначала работает, но медленно, потом виснет все. Но Nsd все равно постоянно растет, и если потом превысит предельно допустимое для системы - все упадет - too many open files. Это предположение. не проверял. Nsd при проверке доросло только до 6, дальше на запросы перестал отвечать сервер. правда, я не менял условия цикла, я только убрал shutdown. |
||||
|
|||||
MnxVol |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 15.1.2008 Репутация: нет Всего: нет |
Кстати, в последнее время замечаю, что если я вместо shutdown вызываю close, то работает, но нестабильно, во-первых очень медленно, во-вторых, недолго))) а если вызываю close после shutdown, происходит то же самое, работает медленно и нестабильно. Но значение Nsd меняется и в том и в другом случае
|
|||
|
||||
feodorv |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 10 Всего: 45 |
Только что обратил внимание, что код на перле использует UDP.
Ну правильно. Схема-то какая должна быть:
для одного клиента. Для нескольких нужно изыскивать более изощрённую схему. -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||
|
|||||
boostcoder |
|
|||
![]() pattern`щик ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 5458 Регистрация: 1.4.2010 Репутация: 13 Всего: 110 |
именно по этому я и не приемлю использование системного API, а предпочитаю концентрироваться на решении задачи.
|
|||
|
||||
MnxVol |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 15.1.2008 Репутация: нет Всего: нет |
а разве суть неблокирующих сокетов не в одновременном ожидании больше чем одного подключения? код на perl использует udp, вы правы, пришлось поменять код на tcp для достижения цели, видимо, cisco поменяли протокол. При использовании udp не работает, tcp - все прекрасно. В том то и дело, что дана установка использовать системные API. Не могу отойти от нее. Подскажите тогда в какую сторону сейчас смотреть. |
|||
|
||||
feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 10 Всего: 45 |
Это всё прописывается на циске. Смотрите соответствующий мануал.
Простите, но в Вашем коде никакой сути неблокирующих сокетов не просматривается. ЗаводИте список клиентов, список сокетов и т.д. Какие проблемы? Однако от этого схема не изменится. Вот маловероятно, что циска устанавливает новое соединение на новый вопрос, скорее всего, она пользуется старым соединением. И именно это уже установленное соединение Вы бросаете на произвол судьбы - ни close, ни чтения/записи (ну, кроме одного единственного). Вы пробовали на этом же соединении читать следующие записи? Прочли запись, посмотрели в базу данных, послали ответ. И всё по новой. Соединение закрылось (например, при ребуте циски), возвращаемся к accept. PS Для данной задачи UDP значительно проще. Поищете команды циски, которые прописывают сервер проверки и протокол обмена. Настоятельно советую))) -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
Олег2005 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 421 Регистрация: 26.5.2005 Где: Рига Латвия Репутация: 6 Всего: 11 |
Попробую изложить свое представление о "неблокирующих" и других сокетах. Блокирующих, неблокирующих или асинхронных сокетов в природе не существует. Сокет - это сложный конгломерат-абстракция. В простоте - это как временный рабочий файл - так он и трактуется в *никсах. Блокируют ход программы - операции ввода/вывода, выполняющиеся с этим "псевдорабочим временным файлом". Потому операция connect() - это типичная блокирующая операция. Типично блокирующей операцией я вляется и accept(). Что означает тогда к примеру неблокирующий connect()? Это означает, что типично блокирующую функцию запускают в несвойственном ей режиме, который не является для нее естественным. Потому connect() и отдает сразу управление на следующую команду программы, возвращая SOS - EWOULDBLOCK. И теперь задача дальнейшего кода - все проверить, как же все-таки реально через некоторое время завершится connect(). Вот типичное поведение разных функций, для которых проставлен режим неблокирования: В этом случае работа этого сокета для разных сокетных операций осуществляется следующим образом: · accept() завершает работу сразу же с ошибкой EWOULDBLOCK; · connect() завершает работу сразу же с ошибкой EINPROGRESS; вызывающий процесс продолжит свое выполнение в любом случае, даже если на установку соединения потребуется несколько десятков секунд; · recv(), read() или recvfrom() возвратят -1 (с применением флагов FIONBIO или FNDELAY функции ioctl()) или 0 (O_NDELAY- функция fcntl()) при отсутствии считываемых данных; выставляется ошибка EWOULDBLOCK или EAGAIN. Потому ваш вопрос так сказать повисает в воздухе. Подключения ждет модуль TCP, и в ходящие подключения буферизируются в очереди прослушивающего сокета. accept() висит (блокирует) до тех пор, пока в очереди полностью установленных соединений прослушивающего сокета не появится очередной готовый запрос на обслуживание. Как только запрос появился - accept() cразу создает новый присоединенный сокет и возвращает управление на следующую команду. Насчет асинхронности. Есть функции, которые по жизни сделаны неблокирующими. Не нужны ни ioctl или что еще. Этот режим для них родной...... Это сообщение отредактировал(а) Олег2005 - 6.11.2012, 18:14 |
|||
|
||||
feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 10 Всего: 45 |
Вроде бы это оно ![]() -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
MnxVol |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 15.1.2008 Репутация: нет Всего: нет |
не совсем, у меня команда ip urlfilter server vendor n2h2 10.10.10.10 - и из допустимых параметров дальше outside Specify if the server is on the outside network port Specify URL filter server port number retrans Specify retransmission count timeout Specify retransmission timeout vrf Specify VRF <cr> так что я предположил что по крайней мере в моем случае буду использовать tcp. Олег2005, спасибо за подробное объяснение. feodorv, если я вас правильно понял, мне лучше поменять концепцию с неблокирующих на другие?) попробую. Спасибо, чуть позже отчитаюсь о новом варианте. |
|||
|
||||
feodorv |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 10 Всего: 45 |
Я хоть слово сказал против неблокирующих сокетов? Я двумя руками за. Было бы у меня 10 рук, был бы десятью за. Но ведь надо понимать, что это за зверь - неблокирующий сокет. Вот у Вас в коде применяется recv на неблокирующем сокете. Правильно применяется? Нет. Потому что при работе с неблокирующими сокетами нужно ожидать наступления некоторого события, для чего очень важен вызов select. С помощью этого вызова можно ожидать наступления сразу массы событий от массы же сокетов (и файловых дескрипторов). Но наступления события нужно ожидать (вызовы с блокирующим сокетом просто не вернут управление в программу, пока не наступит ожидаемое событие). У Вас в коде где ожидание события "готовы данные для чтения на таком-то сокете"??? Его нет. Я не против блокирующих сокетов, я против неправильного их использования))) Неблокирующие сокеты позволяют работать сразу с несколькими клиентами, позволяя при этом ожидать подключения новых, в одном единственном потоке. Если у Вас такой клиент один (та самая циска), то смысла в использовании неблокирующих сокетов нет. Да, в этой ситуации достаточно одного блокирующего (nsd). Более того, напишите грамотную программу с участием блокирующего сокета, которая бы постоянно читала бы из сокета nsd (и постоянно бы отвечала туда же). А не требовала бы от циски каждый раз после очередного таймаута переустанавливать соединение с сервером проверки.
Очень жаль. -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||
|
|||||
feodorv |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 10 Всего: 45 |
Ну, я вижу код приблизительно таким:
А уже process_socket анализирует пришедшие 20 байт, если нужно, дочитывает из сокета оставшееся и посылает ответ:
при очень важном условии: читается из сокета ровно столько, сколько запрошено, и пишется туда ровно столько, сколько запрошено (т.е. если прочитано меньше, надо дочитывать, если записано меньше, нужно дозаписывать остаток). Предварительно нужно убедиться, что размер структуры client_data ровно 20 байт, если нет - воспользоваться #pragma pack Это сообщение отредактировал(а) feodorv - 16.11.2012, 16:46 -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||
|
|||||
MnxVol |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 15.1.2008 Репутация: нет Всего: нет |
feodorv, спасибо за помощь! При таком раскладе все работает. По крайней мере уже лучше. Правда, оператор case пришлось все же заменить на if, почему-то не хочет у меня case по нормальному с константами работать, а когда прописываю конкретно число - сравнивая два одинаковых числа попадает на default. Спасибо огромное!
|
|||
|
||||
![]() ![]() ![]() |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Сети | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |