Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 30
×

Структура консольного приложения на Си под Линукс

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

Всем доброго времени суток.

Была поставлена задача написать консольное приложение на си под линукс. Интерфейс приложения должен был поддерживать текстовые комманды в терминале (типа start, stop, help, select , show и.т.д.), причем после ввода соответствующей комманды должен был прерываться основной цикл программы и выполняться соответствующая подпрограмма.

Вопрос по структуре подобных приложений.

Поскольку я с таким раньше не сталкивался то, вероятнее всего, выбрал не самый лучший вариант реализации, а именно: main -> fork -> (menu process(parent), child process(main loop)). В родительском процессе выделяется кусок общей памяти в которую попадает комманда при вводе с клавиатуры, в процессе -потомке идет выполнение основного цикла с постоянной проверкой общей памяти.

Ссылка на программу github.com/...​Onanko/tcp-ip-sniffer.git

Подскажите пожалуйста альтернативные, более правильные пути реализации подобного.

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Артем, если задание еще актуально и задание звучит так, как его ниже описал Анлпей Чернявский, посмотри как это сделано в проекте KADNode.
github.com/mwarning/KadNode

Это тестовое у вас было, что ли?)

Ну я это уже нашла, потому и уточнила, правильно ли поняла ситуацию

Большое спасибо за ответ! Теперь стало понятно как нужно было реализовать коммуникацию между процессами.

Ну мы и задание видели только в интерпритации топикстартера. хз как оно в оригинале звучало.

Честно говоря, начиная тему хотел просто узнать варианты построения приложений подобных описанному в топике.

В требованиях было необходимо сделать сервис для сбора статистики о сетевом трафике: демон — сниффер (чего я не сделал) и интерфейс коммандной строки — другой процесс для общения с демоном.

Теперь то уже понятно, что должно было получится.

Зачем форкаться? Уже давно нити придумали. pthread гуглите. И вообще, я бы подобное на Go писал.

в линуксе разница между этими двумя подходами минимальна
stackoverflow.com/a/4855101/6275324

Очень странный способ парсинга и система имен. Если я правильно понял логику, строка с IP живет в структуре с названием node, у которой есть дети-ноды под все возможные цифры, и при появлении некоторой цифры происходит что-то вообще странное:
if (current -> children[i] == NULL)
{
node* newNode = createNewNode();
current -> children[i] = newNode;
current = newNode;
}
— создаем новую ноду, записываем ее в дети текущей, а потом поверх текущей записываем свежесозданную. Логика мне непонятна. Если это все работает — расскажите как?

Работает.

current -> children[i] = newNode;
Это ж указатели, по этому не
записываем ее в дети текущей, а потом поверх текущей записываем свежесозданную
, а делаем так, что и-тый «ребенок» текущего узла ссылается на адрес новосозданного узла, а потом текущим становится последний.

а, указатель на первую таки сохраняется, это было не так просто заметить )) Но вопрос остается — зачем так сложно? Это ведь ничем не лучше чем хранить айпишник просто как строку, и идти по ней посимвольно

Одним из требований было обеспечить поиск айпишника с O(log(n))

А каким образом это реализуется в данном подходе?

...а, в итоге понял. Но — определенно неочевидно, я бы совсем иначе писал

Я бы вначале погуглил опенсорс решения, и поизучал их. Одно из первых в выдаче github.com/michaelmacinnis/oh

В реале для этого пользуются собственно батником, написанным на каком угодно языке, на котором удобно общаться с командной строкой. Оптимальный вариант — пиши родной шелл.
А вот уже основному процессу, который по сути отдельное приложение, идёт сигнал. PID процесса при этом сам процесс кладёт файлом в конкретное место на файловой системе.

Итого — С тебе здесь не уместен ни коим боком. Но если требования на С — пиши на нём. Задача так понимаю учебная, а значит не заморачивайся сильно с обработкой формата ввода. Сделай чтобы понимала конкрентые команды в одной единственно возможной формулировке и возьми с полки печеньку. Реально писать интерфейс командной строки на С тебе не придётся никогда, есть готовые библиотеки на другие человеческие языки.

Интерфейс приложения должен был поддерживать текстовые комманды в терминале
GNU readline либо не-GPL альтернативы

Как про мне, не обязательно несколько процессов форкать.
Можно написать однопроцессное приложение — multi threading ( man7.org/...an3/pthread_create.3.html ).

Коментар порушує правила спільноти і видалений модераторами.

Коментар порушує правила спільноти і видалений модераторами.

Типова реалізація:

	pcapfd = pcap_get_selectable_fd()
	cmdfd = ...

	while(1)
	 {
		poll({cmdfd, pcapfd})

		if(POLLIN cmdfd)
			read_cmd_from(cmdfd);
		if(POLLIN pcapfd)
			pcap_dispatch();
	}

Це все в одному процесі.

IPC через shm можна робити, але не так, і для такої задачі це погана ідея.
Якщо у вас є fork, майже завжди десь має бути waitpid.

Я думал над реализаций в одном процессе, но уперся в то, что программа останавливалась и ожидала ввода с клавиатуры когда в цикле доходила до fgets(). Насколько я понимал тут нужно было вводить ограничения по времени такого ожидания, что могло привести к потере пакетов, либо добавлять второй поток/процесс.

Дело в том, что некоторые подпрограммы тоже зациклены, и как их прервать таким макаром я не знал

Согласен, плохо сформулировал.
Требование С.
Присутствует 2 процесса, но, как я уже понял лучше бы использовал 2 потока в одном процессе, либо вообще попробовать сделать как говорит Jorzchyk Pushysty. Буду разбираться.

Погугли как сделать non-blocking keyboard polling, linux.

И pcap, и комманды должны читаться в non-blocking mode.

www.tcpdump.org/pcap3_man.html
www.tcpdump.org/...ap_setnonblock.3pcap.html

A handle can be put into ``non-blocking mode’’, so that those routines will, rather than blocking, return an indication that no packets are available to read ... Non-blocking mode is often combined with routines such as select(2) or poll(2) or other routines a platform offers to wait for any of a set of descriptors to be ready to read.

Для комманд, это выглядит как bytes = read(cmdfd, buf, sizeof(buf)) ровно один раз после POLLIN, и парсинга buf[0:bytes]. Если ввод типа комманда-Enter-комманда-Enter, там всегда будет одна комманда.

Підписатись на коментарі