The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Пишем "ДЕМОНА" своими руками (daemon gcc proccess)


<< Предыдущая ИНДЕКС Исправить src / Печать Следующая >>
Ключевые слова: daemon, gcc, proccess,  (найти похожие документы)
From: Шевелёв Денис <alma_tv_denis@mail.ru.> Newsgroups: email Date: Mon, 24 Mar 2008 14:31:37 +0000 (UTC) Subject: Пишем "ДЕМОНА" своими руками Итак целью нашей с Вами задачи встал вопрос написания сетевого демона для управления чем либо на Linux из под Windows с различных мест. В каждой реализации Linux всегда присутствует библиотека GNU libc. Мы не будем использовать объектно-ориентированное-программирование (ООП), а возьмем стандартный язык разработки под Linux - это Cи. Статья рассчитана на пользователей только начинающих изучать язык Си. Краткая справка: Разработка системы GNU началась 27 сентября 1983 года, когда Ричард Столлмэн опубликовал объявление о проекте в группах новостей net.unix-wizards и net.usoft. 5 января 1984 года Столлмэн уволился из Массачуссетского технологического института с целью посвятить своё время написанию свободной операционной системы, а также для того, чтобы институт не мог претендовать на какие-либо права на исходный код системы. Первой программой GNU стал текстовый редактор Emacs. В настоящее время система GNU/Linux, более широко известная как просто Linux, достаточно распространена (особенно на рынке серверов) и является вполне завершённой. Она состоит из большого количества программ проекта GNU (в первую очередь системных утилит и GNU toolchain), ядра Linux - части системы, отвечающей за выполнение других программ, включающей драйверы устройств и т. п., - и множества других свободных программ. И так преступим к написанию сетевого ЭХО сервера с признаками "демонизма". Файл назовем daemon.c cd / --переходим в корневой каталог mkdir myprogonlinux --создаем папку где будем писать демона cd myprogonlinux touch daemon.c --создаем файл vi daemon.c и так файл daemon.c #include <stdio.h> //--список объявлений и используемых нами готовых библиотек Cи #include <string.h> //--подробно о каждой библиотеке можно узнать в man #include <sys/stat.h> //--например man stdio и.т.д #include <sys/types.h> #include <netinet/in.h> #include <sys/time.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> #include <resolv.h> #include <errno.h> Любая программа на Си (если это не вспомогательный модуль где описываются выполняемые универсальные функции)начинается с главной процедуры или функции main #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/time.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> #include <resolv.h> #include <errno.h> int Daemon(void) // --это объявление функции для нашего демона то есть реализация ЭХО сервера int main(int argc, char* argv[]) //--это наша главная процедура с которой начинается программа { pid_t parpid; if((parpid=fork())<0) //--здесь мы пытаемся создать дочерний процесс главного процесса (масло масляное в прямом смысле) { //--точную копию исполняемой программы printf("\ncan't fork"); //--если нам по какойлибо причине это сделать не удается выходим с ошибкой. exit(1); //--здесь, кто не совсем понял нужно обратится к man fork } else if (parpid!=0) //--если дочерний процесс уже существует exit(0); //--генерируем немедленный выход из программы(зачем нам еще одна копия программы) setsid(); //--перевод нашего дочернего процесса в новую сесию Daemon(); //--ну а это вызов нашего демона с нужным нам кодом (код будет приведен далее) return 0; } Я думаю многие после данного объяснения ничего не поняли. Поясняю на пальцах Любая программа на Си начинает исполнятся с главной процедуры main. При запуске программы создается процесс (на время работы программы). Мы просто создаем дочернюю копию этого процесса и переводим его в новую сессию, что бы он не блокировал текущую вашу сессию. для лучшего понимания (не поленитесь) перепишем выше приведенный код и сделаем два режима работы "демон","не демон" #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/time.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> #include <resolv.h> #include <errno.h> int Daemon(void) int main(int argc, char* argv[]) { pid_t parpid; if (argc < 2) { printf("Usage ./daemon -d for daemon or ./daemon -i for interactive\n"); exit(1); } if (strcmp(argv[1],"-i")==0) Daemon(); else if (strcmp(argv[1],"-d")==0) { if((parpid=fork())<0) { printf("\ncan't fork"); exit(1); } else if (parpid!=0) exit(0); setsid(); Daemon(); } else { printf("Usage ./daemon -d for daemon or ./daemon -i for interactive\n"); exit(1); } return 0; } то есть программу мы будем запускать с ключами "-d",как демон и "-i", как не демон. Итак преступаем к написанию нами функции Daemon() #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/time.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> #include <resolv.h> #include <time.h> #include <errno.h> #define PORT_CON 6823 //--определяем порт который будет прослушивать наш эхо сервер struct sockaddr_in client_name;//--структура sockaddr_in клиентской машины (параметры ее нам неизвестны. Мы не знаем какая машина к нам будет подключаться) int size = sizeof(client_name);//--размер структуры (тоже пока неизвестен) int client_socket_fd; //--идентификатор клиентского сокета //--вобще теория сокетов более подробно будет рассмотрена в следующей статье char sockbuff[1024]; //--наш буфер обмена информацией с клиентом time_t now; struct tm *ptr; char tbuf[80]; int Daemon(void) char* getTime(); char * getTime() //--функция определения времени в нужном формате { char *ret; ret=(char*)malloc(100); bzero(ret,100); time(&now); ptr = localtime(&now); strftime(tbuf,80,"%Y-%B-%e %H:%M:%S",ptr); ret=tbuf; return (ret); } int main(int argc, char* argv[]) { pid_t parpid; if (argc < 2) { printf("Usage ./daemon -d for daemon or ./daemon -i for interactive\n"); exit(1); } if (strcmp(argv[1],"-i")==0) Daemon(); else if (strcmp(argv[1],"-d")==0) { if((parpid=fork())<0) { printf("\ncan't fork"); exit(1); } else if (parpid!=0) exit(0); setsid(); Daemon(); } else { printf("Usage ./daemon -d for daemon or ./daemon -i for interactive\n"); exit(1); } return 0; } int Daemon(void) { FILE *logfile; //--лог для подключившихся клиентов причем для каждого будет свой int socket_fd,nbytes; //--объявляем идентификатор сокета нашего сервера char host[20]; char *namlog; void sig_child(int);//--объявление функции ожидания завершения дочернего процесса pid_t pid; struct sockaddr_in name;//--структура sockaddr_in для нашего сервера на сей раз ее придется заполнить namlog=(char*)malloc(25); socket_fd=socket(PF_INET,SOCK_STREAM,0); //--создаем сокет сервера в данном случае TCP, если бы мы использовали флаг SOCK_DTGRAM то получили бы сокет UDP name.sin_family=AF_INET; //--говорим что сокет принадлежит к семейству интернет name.sin_addr.s_addr=INADDR_ANY; //--наш серверный сокет принимает запросы от любых машин с любым IP-адресом name.sin_port=htons(PORT_CON); //--и прослушивает порт 6823 if(bind(socket_fd, &name, sizeof(name))==-1) //--функция bind спрашивает у операционной системы,может ли программа завладеть портом с указанным номером { perror("bind"); //--ну если не может,то выдается предупреждение exit(0); //--соответственно выход из программы } listen(socket_fd,20); //--перевод сокета сервера в режим прослушивания с очередью в 20 позиций for(;;) //--бесконечный цикл (как так?... спросите ВЫ. У нас же сервер,который должен постоянно принимать и обслуживать запросы и работать пока его не погасят насильно) { signal(SIGCHLD,sig_child); //--если клиент уже поработал и отключился ждем завершение его дочернего процесса client_socket_fd = accept (socket_fd,&client_name,&size); //--подключение нашего клиента if (client_socket_fd>0) //--если подключение прошло успешно { if ((pid=fork())==0) //--то мы создаем копию нашего сервера для работы с другим клиентом(то есть один сеанс уде занят дублируем свободный процесс) { inet_ntop(AF_INET,&client_name.sin_addr,host,sizeof(host));--в переменную host заносим IP-клиента bzero(namlog,25); strcpy(namlog,host); strncat(namlog,"\0",1); strcat(namlog,".log"); //--для каждого соединения делаем свой лог if(fopen(logfile,namlog,"a+")!=NULL); //--создаем лог файл подключившегося клиента { fprintf(logfile,"%s Connected client:%s in port: %d\n",getTime(),host,ntohs(client_name.sin_port)); fflush(logfile); fclose(logfile); } do { bzero(sockbuff,1024); //--чистим наш буфер от всякого мусора nbytes=read(client_socket_fd,sockbuff,1024); //--читаем из в буфер из клиентского сокета strncat(sockbuff,"\0",1); //--незабываем символ конца строки if(fopen(logfile,namlog,"a+")!=NULL); { fprintf(logfile,"%s Client send to Server:%s\n",getTime(),sockbuff); fflush(logfile); //--эту запись в лог файл конечно можно оформить ввиде отдельной функции fclose(logfile); //--даную функцию вы должны написать уже сами для тренировки } sendto(client_socket_fd,sockbuff,strlen(sockbuff),0,&client_socket_fd,size); //--и отсылаем полученую информацию назад if(fopen(logfile,namlog,"a+")!=NULL); { fprintf(logfile,"%s Server answer to client:%s\n",getTime(),sockbuff); fflush(logfile); fclose(logfile); } } while(nbytes > 0 && strncmp("bye",sockbuff,3)!=0); //--выполняем цикл пока клиент не закроет сокет или пока не прилетит сообщение от клиента "bye" if(fopen(logfile,namlog,"a+")!=NULL); { fprintf(logfile,"%s Close session on client:%s\n",getTime(),host); fflush(logfile); fclose(logfile); } close(client_socket_fd); //--естествено закрываем сокет exit(0); //--гасим дочерний процесс } else if (pid > 0) close(client_socket_fd); } } } void sig_child(int sig) //--функция ожидания завершения дочернего процесса { pid_t pid; int stat; while ((pid=waitpid(-1,&stat,WNOHANG))>0) { } return; } Ну вот и все.....Демон готов к работе Прежде чем использовать....нужно откомпилировать и убрать возможные ошибки Итак.....компиляция //для RedHat,FreeBCD,Slackware,OpenSuSe cd / cd myprogonlinux gcc daemon.c -g -lnsl -lresolv -o daemon //для Solaris cd / cd myprogonlinux gcc daemon.c -g -lnsl -lsocket -o daemon //у Вас должен появиться скомпилированый выполняемый файл daemon //запускаем в режиме демона ./daemon -d //проверяем pgrep daemon 3102 //тушим pkill daemon //запускаем в интерактивном режиме ./daemon -i //Ну и конечно обнаруживаем что наша сессия зависла поможет только Ctrl+C Для проверки нашего демона запускаем его с ключем -d и в любой программной оболочки типа дельфи или С++Builder пишем простого клиента //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::ClientSocket1Read(TObject *Sender, TCustomWinSocket *Socket) { AnsiString S=""; S=Socket->ReceiveText(); Memo1->Lines->Add(S); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { ClientSocket1->Host=Edit1->Text; ClientSocket1->Port=StrToInt(Edit2->Text); ClientSocket1->Open(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { ClientSocket1->Socket->SendText(Edit3->Text); } //--------------------------------------------------------------------------- Ну форму приводить не буду. Кто знаком с Дельфи и С++Builder тот разберется что к чему и раставит компоненты как будет удобно Ну вот и все...... За дополнительными вопросами обращайтесь по адресу [email protected]. С удовольствием на них отвечу..... Статья написана из соображений недоступности рускоязычной литературы по данным вопросам, а также многим моим знакомым, которые относятся к программированию под Linux как к чему-то сверхестественному. С уважением ! Денис.

<< Предыдущая ИНДЕКС Исправить src / Печать Следующая >>

Обсуждение [ Линейный режим | Показать все | RSS ]
  • 1.1, PavelR (??), 05:40, 26/03/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/

    >Мы не будем использовать объектно-ориентированное-программирование (ООП)
    >(в некоторых случаях для него нужны иксы(X windows)),

    В шоке, нах, прям с первых строк.

     
     
  • 2.3, Pahanivo (??), 18:40, 26/03/2008 [^] [^^] [^^^] [ответить]  
  • +/
    мда - даже код смотреть не буду
     
     
  • 3.4, Andrey (??), 17:28, 13/05/2008 [^] [^^] [^^^] [ответить]  
  • +/
    Хехе. А время на коменты выделил.
     

  • 1.2, Architect (?), 11:10, 26/03/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Статья написана из соображений недоступности рускоязычной литературы по данным вопросам,
    а также многим моим знакомым, которые относятся к программированию под Linux
    как к чему-то сверхестественному.

    "Профессиональное программирование для Linux" вышла еще в 2001 году. Может посматривать вокруг себя надо)) Хотя этот труд обращает на себя внимание))

     
     
  • 2.16, Шевелв Денис (?), 06:21, 05/12/2008 [^] [^^] [^^^] [ответить]  
  • +/
    >Статья написана из соображений недоступности рускоязычной литературы по данным вопросам,
    >а также многим моим знакомым, которые относятся к программированию под Linux
    >как к чему-то сверхестественному.
    >
    >"Профессиональное программирование для Linux" вышла еще в 2001 году. Может посматривать вокруг
    >себя надо)) Хотя этот труд обращает на себя внимание))

    Вы имеете ввиду книгу авторов (Марк Митчел, Джеффри Оулдем, Алекс Самьюэл) ну так это пародия на язык. Те темы, которые авторы понимают описаны отлично, но где они сомневаются ограничено общими словами.


     

  • 1.5, naquad (??), 18:06, 12/06/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    ну посмотрел в код, убила функция getTime()
    в которой есть строчка: ret=(char*)malloc(100);
    но вот какая грабля: нигде это не освобождается,
    так что это утечка памяти. явная. грубая.
    дальш читать не стал
     
     
  • 2.13, Шевелв Денис (?), 06:09, 05/12/2008 [^] [^^] [^^^] [ответить]  
  • +/
    Да будет ВАМ известно что память освобождается когда умирает процесс
     

  • 1.6, alexx (??), 07:33, 25/06/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    а ничего, если демон своим perror-oм будет гнать в stderr ? ;)


     
     
  • 2.14, Шевелв Денис (?), 06:10, 05/12/2008 [^] [^^] [^^^] [ответить]  
  • +/
    Ничего..... иначе как новичёк поймет от чего демон не работает
     

  • 1.7, VlSePr (?), 04:20, 13/07/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Там просто нету строчки что программу для использования надо доработать напильником :)
     
     
  • 2.15, Шевелв Денис (?), 06:14, 05/12/2008 [^] [^^] [^^^] [ответить]  
  • +/
    >Там просто нету строчки что программу для использования надо доработать напильником :)
    >А Вы наверное хотели чтобы я профессионально написал код но коменты сократил.......иногда для понимания чем то жертвуешь в угоду читающему. И еще замечу , что я никому никогда ничего не писал. Все кто обращался писали сами после объяснения.
     

  • 1.8, Zving (?), 17:12, 08/09/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    тихий ужас... Одна такая статья может испортить несколько начинающих программистов, если они вдруг решат учиться по данной статье.
    дескрипторы не закрываются, код возврата половины функций не проверяется, cwd не меняется....
    Аффтор,видимо, один из тех, кто думает, раз все у него заработало - то он все сделал правильно и можно учить других.
     
     
  • 2.17, Шевелв Денис (?), 06:23, 05/12/2008 [^] [^^] [^^^] [ответить]  
  • +/
    Ужас в журналах не печатают
     
     
  • 3.20, kandrew (?), 17:28, 31/12/2008 [^] [^^] [^^^] [ответить]  
  • +/
    Еще как печатают, иногда даже воруют статьи с опеннета 2-3 годовой давности и печатают в журналах под своим именем. :)
     

  • 1.9, ZeRo (?), 20:56, 24/09/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Нда, НОВИЧКАМ НЕ ЧИТАТЬ !!!! Вот и все что можно сказать
     
     
  • 2.23, Гость (?), 07:37, 18/03/2009 [^] [^^] [^^^] [ответить]  
  • +/
    >Нда, НОВИЧКАМ НЕ ЧИТАТЬ !!!! Вот и все что можно сказать

    а что читать новичкам?

     

  • 1.10, проходящий мимо (?), 21:12, 30/09/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Жесть...
     
  • 1.11, dexter (??), 11:11, 01/10/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Почему не посмотреть на принцип работы демона? Мне кажется автор это здесь хотел показать, а не навыки программинга в Си :) Я вообще практически "0" в Си, но стоит вопрос написать демона. Как и примерно его делать -- не знаю. Мне пофиг какие там дискрипторы, cwd и прочее не закрыты и не используются, прочитал и стало вообщем-то ясно как должен выглядеть демон. Всё остальное от программера зависит ;)
     
     
  • 2.18, Шевелв Денис (?), 06:25, 05/12/2008 [^] [^^] [^^^] [ответить]  
  • +/
    Так держать!
     

  • 1.12, Шевелв Денис (?), 11:09, 04/12/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    текст кода был взят из первых моих программ, которые мне приходилось писать практически вслепую... и если, кого там смущает malloc? да пусть новички познакомятся с этой функцией......И скорее всего они не знают о функции getopt(). Половина не знает как работать с файлами, половина вообще о сигналах ничего не знает. Другая половина никогда не работала с сокетами, файлами. Данный пример охватывает все возможности языка СИ.
    Конечно можно было написать так
    char *getTime(char *time_format)
    {
        struct tm *tm;
        time_t now;
        static char rt[80];
        now = time(0);
        tm = localtime(&now);
        strftime(rt,sizeof(rt),time_format,tm);
        return (rt);
    }
    половина бы пропустила директиву static и на выходе получила бы абракадабру.
    Так что код приведенный здесь рассчитан на начальный уровень программирования. И чтоб все получилось с первого раза.


    Наверное большинство, кто высказался здесь.....сразу родились этакими суперпрограмерами. И наверно утилиту Valgrind впитывали с молоком матери.

     
     
  • 2.30, Serj (??), 18:44, 19/05/2014 [^] [^^] [^^^] [ответить]  
  • +/
    Ты в создании сокета в функции Daemon() при создании самого сокета первым п-м используешь const
    PF_INET, а в структуре sockaddr_in name в поле name.family используешь const AF_INET.
    Вопрос: скажи,а это никак не скажется на работе программы?(так как я и там и там в сокетах использовал
    const AF_INET)

     

  • 1.19, NaN (?), 12:00, 17/12/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Слишком сложно получается, по-моему, можно было бы обойтись и меньшей кровью
     
  • 1.21, msa (??), 16:08, 09/01/2009 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Нормальная статья. Как отправная точка, я бы сказал, незаменимая. В программе - готовый скелет для демона, а глюки можно поправить, если руки растут не из жо...
     
  • 1.22, kerya (?), 19:20, 04/02/2009 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    to Zving: А мне бы было интересно увидеть от Вас статью-дополнение или статью-ответ.
     
     
  • 2.26, craftmail (?), 14:55, 29/11/2011 [^] [^^] [^^^] [ответить]  
  • +/
    Мда много умников сразу накинулось прокоментировать...
    Но ни один из коментарием не стоит даже одного слова из статьи...
     

  • 1.24, pinkpiton (??), 11:39, 05/02/2010 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    http://linuxportal.ru/entry.php/2361_0_3_0_C/
    статья 4-го года переведена в 6-м
     
  • 1.25, fr33z3 (?), 11:59, 25/08/2011 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Необходимо добавить библиотеку stdlib.h, в которой располагается метод exit
     
  • 1.27, Vasya (??), 13:43, 06/07/2012 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Спасибо за статью. Как всегда, после написания появляются "умники", которые конкретно никогда никому не помогают, а могут только лажать, да в гугл отсылать.
     
  • 1.28, illy (?), 16:42, 30/08/2012 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Достаточно давно уже на общественных началах кодю открытый тулкит для разработки серверов на плюсах: http://isl.storozhilov.com/ - может это как-то может помочь начинающим? Да и вообще, может кто мнение свое скажет, надо ли оно? А то я пишу, пишу... :)
     
  • 1.29, Serj (??), 18:20, 19/05/2014 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Большое спасибо за код! Я как раз искал пример демона для новичков.
     
  • 1.31, Andrey (??), 13:11, 31/08/2015 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    http://admin-world.net/content/view/17/29/
    Советую почитать, описано достаточно хорошо.
     

    игнорирование участников | лог модерирования

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Партнёры:
    PostgresPro
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2024 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру