The OpenNET Project / Index page

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

Пишем "ДЕМОНА" своими руками (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 тот разберется что к чему и раставит компоненты как будет удобно Ну вот и все...... За дополнительными вопросами обращайтесь по адресу alma_tv_denis@mail.ru. С удовольствием на них отвечу..... Статья написана из соображений недоступности рускоязычной литературы по данным вопросам, а также многим моим знакомым, которые относятся к программированию под 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 [^] [ответить] [смотреть все] [показать ветку]
  • +/
    Вы имеете ввиду книгу авторов Марк Митчел, Джеффри Оулдем, Алекс Самьюэл ну та... весь текст скрыт [показать] [показать ветку]
     
  • 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 [^] [ответить] [смотреть все] [показать ветку]  
  • +/
    Пишем 'ДЕМОНА' своими руками (daemon gcc proccess)... весь текст скрыт [показать] [показать ветку]
     
  • 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 [ответить] [смотреть все]  
  • +/
    текст кода был взят из первых моих программ, которые мне приходилось писать прак... весь текст скрыт [показать]
     
     
  • 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:      
    Заголовок:
    Текст:





      Закладки на сайте
      Проследить за страницей
    Created 1996-2017 by Maxim Chirkov  
    ДобавитьРекламаВебмастеруГИД  
    Hosting by Ihor