Как добавить "ifconfig" в файл.txt на языке C?
Я пытаюсь получить свой собственный IP-адрес с C. Идея состоит в том, чтобы получить вывод "ifconfig", поместить его в файл.txt и извлечь значения inet и inet6. Я пытаюсь записать вывод ifconfig в файл.txt:
#include <stdio.h>
#include <stdlib.h>
#include <string>
int main ()
{
char command[1000];
strcpy(command, "ifconfig");
system(command);
FILE *fp = fopen("textFile.txt", "ab+");
//... how to write the output of 'system(command)' in the textFile.txt?
fclose(fp);
//... how to scraping a file .text in C ???
return 0;
}
Спасибо за любую помощь и предложение, Стефано
2 ответа
В Linux используйте man 7 netdevice
описывает интерфейс, который вы можете использовать, как уже ответил Аниш Гоял.
Это очень просто и надежно, и использует очень мало ресурсов (так как это всего лишь несколько системных вызовов). К сожалению, это специфично для Linux и делает код непереносимым.
Это можно сделать переносно. Я опишу переносимый вариант здесь, потому что специфичный для Linux вариант довольно тривиален. Хотя этот подход довольно сложен для простого получения IP-адресов локального хоста, шаблон на удивление часто полезен, поскольку он может скрывать специфические для системы причуды, в то же время позволяя системным администраторам настраивать поведение.
Идея переносимого решения заключается в том, что для получения информации вы используете небольшую вспомогательную программу или сценарий оболочки и выводите ее в некотором простом для анализа формате в основную программу. Если ваше приложение называется yourapp
Обычно такие помощники устанавливаются в /usr/lib/yourapp/
, сказать /usr/lib/yourapp/local-ip-addresses
,
Лично я бы рекомендовал использовать сценарий оболочки (чтобы системные администраторы могли легко редактировать помощники, если им нужно настроить поведение) и выходной формат, где каждый интерфейс находится на отдельной строке, поля разделены пробелами, возможно,
inet interface-name ipv4-address [имя хоста]*
inet6 имя-интерфейса ipv6-адрес [имя хоста]*
т. е. первый токен определяет семейство адресов, второй токен - имя интерфейса, третий - адрес, за которым, возможно, следуют имена хостов или псевдонимы, соответствующие этому адресу.
Что касается самой вспомогательной программы / сценария оболочки, существует два основных подхода:
Один выстрел
Например, разбор
LANG=C LC_ALL=C ip address
вывод в линуксе. Программа / скрипт завершится после того, как адреса будут напечатаны.непрерывный
Программа / скрипт будет печатать информацию IP-адреса, но вместо выхода она будет работать, пока канал остается открытым, предоставляя обновления, если интерфейсы отключены или появятся.
В Linux программа / скрипт могут использовать DBUS или NetworkManager для ожидания таких событий; не нужно опрашивать (то есть повторно проверять вывод команды).
Сценарий оболочки имеет дополнительное преимущество, заключающееся в том, что он может одновременно поддерживать несколько дистрибутивов, даже операционных систем (по крайней мере, в разных системах POSIX). Такие сценарии часто имеют похожую схему:
#!/bin/sh
export LANG=C LC_ALL=C
case "$(uname -s)" in
Linux)
if [ -x /bin/ip ]; then
/bin/ip -o address | awk \
'/^[0-9]*:/ {
addr = $4
sub(/\/.*$/, "", addr)
printf "%s %s %s\n", $3, $2, addr
}'
exit 0
elif [ -x /sbin/ifconfig ]; then
/sbin/ifconfig | awk \
'BEGIN {
RS = "[\t\v\f\r ]*\n"
FS = "[\t\v\f ]+"
}
/^[0-9A-Za-z]/ {
iface = $1
}
/^[\t\v\f ]/ {
if (length(iface) > 0)
for (i = 1; i < NF-1; i++)
if ($i == "inet") {
addr = $(i+1)
sub(/^addr:/, "", addr)
printf "inet %s %s\n", iface, addr
} else
if ($i == "inet6") {
addr = $(i+2)
sub(/\/.*$/, "", addr)
printf "inet6 %s %s\n", iface, addr
}
}'
exit 0
fi
;;
# Other systems?
esac
printf 'Cannot determine local IP addresses!\n'
exit 1
Скрипт устанавливает локаль в C
/ POSIX
, так что вывод внешних команд будет в локали по умолчанию (на английском и т. д.). uname -s
предоставляет имя ядра (Linux
для Linux), и дальнейшие проверки могут быть выполнены, например, с помощью [
командная оболочка.
Я реализовал скриптлет только для Linux, потому что это машина, на которой я сейчас работаю. (И то и другое ip
а также ifconfig
альтернативы работают на моей машине и дают тот же результат - хотя вы не можете ожидать, что интерфейсы будут в каком-то определенном порядке.)
Ситуации, когда сисадмину может понадобиться редактировать этот конкретный вспомогательный скрипт, включают в себя еще не поддерживаемые системы, системы с новыми основными инструментами и системы, которые имеют интерфейсы, которые должны быть исключены из обычных списков интерфейсов (скажем, тех, которые подключены к внутреннему подчиненному сценарию). сеть, зарезервированная для привилегированных целей, таких как DNS, файловые серверы, резервные копии, LDAP и т. д.).
В приложении C вы просто запускаете внешнюю программу или скрипт оболочки, используя popen("/usr/lib/yourapp/local-ip-addresses", "r")
, который предоставляет вам FILE *
что вы можете прочитать, как если бы это был файл (за исключением того, что вы не можете искать или перематывать его). После того, как вы прочитали все из трубы, pclose()
рукоять:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
/* ... */
FILE *in;
char *line_ptr = NULL;
size_t line_size = 0;
ssize_t line_len;
int status;
in = popen("/usr/lib/myapp/local-ip-addresses", "r");
if (!in) {
fprintf(stderr, "Cannot determine local IP addresses: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
while (1) {
line_len = getline(&line_ptr, &line_size, in);
if (line_len < 1)
break;
/* Parse line_ptr */
}
free(line_ptr);
line_ptr = NULL;
line_size = 0;
if (ferror(in) || !feof(in)) {
pclose(in);
fprintf(stderr, "Read error while obtaining local IP addresses.\n");
exit(EXIT_FAILURE);
}
status = pclose(in);
if (!WIFEXITED(status) || WEXITSTATUS(status)) {
fprintf(stderr, "Helper utility /usr/lib/myapp/local-ip-addresses failed to obtain local IP addresses.\n");
exit(EXIT_FAILURE);
}
Я опустил код разбора, потому что есть так много альтернатив - strtok()
, sscanf()
или даже пользовательская функция, которая разбивает строку на токены (и заполняет массив указателей) - и мой собственный предпочтительный вариант является наименее популярным (последний - пользовательская функция).
Хотя код, необходимый только для этой задачи, практически не стоит того времени, приложения, использующие этот подход, обычно используют несколько таких помощников. Тогда, конечно, имеет смысл выбрать формат данных по конвейеру таким образом, чтобы можно было легко выполнять синтаксический анализ, но поддерживаются все варианты использования. Тогда амортизируемую стоимость легче принять.
Вы на самом деле хотите использовать системные вызовы для достижения этой цели - вместо того, чтобы запускать команду ifconfig.
Здесь такой же вопрос для Linux: использование кода на C для получения той же информации, что и для ifconfig
(Поскольку ifconfig - это команда Linux, я предполагаю, что вы спрашиваете о Linux).
Общая суть заключалась в том, чтобы использовать ioctl()
системный вызов.
В противном случае вы будете разветвлять свой процесс, чтобы разделить его на две части, создав канал из вывода дочернего элемента во вход родительского и вызвав exec для дочернего элемента, чтобы заменить его на ifconfig. Затем вам придется проанализировать строку, если вы хотите извлечь из нее что-нибудь полезное.