Мы — долго запрягаем, быстро ездим, и сильно тормозим.

FreeBSD
  настройка
  подсчёт трафика
  программы
  почтовые системы
  Шелезяки
  Мелочи
  Файловая система
  WWW
  Security
  system
  Games Servers
  X11
  Programming
  Socket сервер на FreeBSD.
  Создание программ на QT4/С++
  PerlQT4 (Использование С++ классов в Perl скриптах)
  CRUD Perl Web
  MVC Catalyst
  Zyxel Configuration
Очумелые Ручки
OpenBSD
Cisco


www.lissyara.su —> статьи —> FreeBSD —> Programming —> Socket сервер на FreeBSD.

Socket сервер на FreeBSD.

Автор: Fastman.


 По ходу работы необходимо было из клиента написанного под Windows запускать скрипты на Unix машине (в качестве которой сейчас у меня FreeBSD 6.1). Пишу в основном на C/C++ поэтому решил не изменять традициям. Опыта программирования под Unix практически не было, поэтому буду рад любым замечаниям. В статье будет показан  "каркас" серверного приложения под FreeBSD. Инструменты:Mc + mcedit + c++ :))) На самом деле сейчас этот кусок проекта очень сильно потолстел, и обзавелся кучей фишек, однако пускай каждый сам решает что может быть прицепленно к этому "каркасу".
Поехали :)
Чтобы не изобретать велосипеды, нарыл в интернете пример небольшой, и на его основе сваял ниже показанный код. Что мы должны получить в итоге ? TCP-демон, который будет слушать определенный порт, принимать данные, и отвечать клиенту. Для обслуживания TCP-демона, будем использовать механизм fork() который создает процесс-потомок, который отличается от родительского только значениями PID (идентификатор процесса) и PPID (идентификатор родительского процесса).
tcp_daemon.cpp:

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <syslog.h>
#include <signal.h>

#include <vector>
#include <string>
#include <fstream>
#include <iostream>

using namespace std;

class tcpdaemon 
{
    protected:
	void daemonize();
	void mainloop();
	void operate(int fd);
	static void sighandler(int signum);

    public:
	void exec();
};

void tcpdaemon::sighandler(int signum)
{
    waitpid(0, 0, WNOHANG);
}

void tcpdaemon::daemonize() 
{
    int pid;
    struct sigaction sa;

    cout << "Server start ok ! " << flush;
    pid = fork();

    switch(pid)
    {
	case 0:
	    setsid();
	    chdir("/");

	    close(0);
	    close(1);
	    close(2);

	    memset(&sa, 0, sizeof(sa));
	    sa.sa_handler = &sighandler;
	    sigaction(SIGCHLD, &sa, 0);

	    openlog("tcp_daemon", 0, LOG_USER);
	    mainloop();
	    closelog();

	    exit(0);

	case -1:
	    cout << "fork() error" << endl;
	    break;

	default:
	    cout << "ok. PID=" << pid << endl;
	    break;
    }
}

void tcpdaemon::mainloop()
{
    int sockfd, fd;
    struct sockaddr_in sa;
    socklen_t n;

    sockfd = socket(PF_INET, SOCK_STREAM, 0);

    if(sockfd != -1)
    {
	memset(&sa, 0, sizeof(sa));

	sa.sin_family = AF_INET;
	sa.sin_addr.s_addr = htonl(INADDR_ANY);
	sa.sin_port = htons(1667);

	if(bind(sockfd, (struct sockaddr *) &sa, sizeof(sa)) != -1)
	{
	    while(1) {
		if(!listen(sockfd, 5))
		{
		    n = sizeof(sa);
		    if((fd = accept(sockfd, (struct sockaddr *) &sa, &n)) != -1)
		    {
			syslog(LOG_NOTICE, "connection from %s", inet_ntoa(sa.sin_addr));

			if(!fork()) 
			{
			    operate(fd);
			}
		    }
		}
	    }
	}
    }
}

void tcpdaemon::operate(int fd)
{
    char c;
    bool finished;
    string cmd, answer;

    finished = false;

    write(fd, answer.c_str(), answer.size());

    while(!finished) 
    {
	cmd = answer = "";

	while(!finished) {
	    finished = read(fd, &c, 1) != 1;

	    if(c == '\n') break; else
	    if(c != '\r') cmd += c;
	}

	if(!finished && !cmd.empty())
	{
	    if(cmd == "info")
	    {
                answer = "First Socket SERVER :)";
	    } 
	    else if(cmd == "version")
	    {
		answer = "version 1.0";
	    } 

	    else if(cmd == "quit")
	    {
		shutdown(fd, 2);
		close(fd);
		finished = true;
	    }

	    else
            {
	    
	    /*
            int i  = system(cmd.c_str());
	    if(i == -1)
	    {
	    answer = "err";
	    }
	    else answer = "ok";
            */
	    }	

	}

	if(!finished && !answer.empty())
	{
	    answer += "\n";
	    write(fd, answer.c_str(), answer.size());
	}
    }

    exit(0);
}

void tcpdaemon::exec() 
{
    daemonize();
}

int main()
{
    tcpdaemon d;
    d.exec();
    return 0;
} 

По хорошему, конечно, нужно разносить в разные файлы определения членов класса, их реализацию и функцию main(), что в последствии и было сделанно.
Чтобы после исправления кода вручную не писать команду компилирования делаем маленький скрипт:
make.sh:

#!/bin/sh
killall tcp_daemon
c++ tcp_daemon.cpp -o tcp_daemon
./tcp_daemon

После запуска, получаем:

# ./make.sh
No matching processes were found
Server start ok ! ok. PID=45635

Естесственно пока у нас не запущен сервер то скажет No matching processes were found, зато в следующий раз после того как мы внесем какие нибудь изменения после запуска этого скрипта прибъется сервер,скомпилируется и запустится.
Теперь можно протестировать на работоспособность всего этого хозяйства:

>telnet localhost 1667
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
info
First Socket SERVER :)
version
version 1.0
quit
Connection closed by foreign host.

Т.е в данный момент введя команды info, version и quit мы убедились что сервер наш работает и адекватно реагирует :) Если присмотреться к коду сервера, то увидим что если комманда введенная не соответствует ни одной из тех что мы ввели то будет выполняться другой кусок кода, у меня там закомментированы следующие строки:

/*
int i  = system(cmd.c_str());
if(i == -1)
{
  answer = "err";
}
else answer = "ok";	
*/

Функция system(const char * string), выполняет команды, указанные в string. Поэтому если вы раскомментируете эти строки(не забыв после этого make.sh запустить:)) и сделаете так:

>telnet localhost 1667
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
uname -a > uname
ok
quit
Connection closed by foreign host.

то в корне у вас появиться файл uname c содержанием в частности у меня:

FreeBSD myserver 6.1-RELEASE FreeBSD 6.1-RELEASE #3: Wed Aug 16 12:43:36 EEST 2006 root@myserver:/usr/obj/usr/src/sys/SMP i386

Будте аккуратней :) Никаких проверок нет, поэтому то же пресловутое rm /-rf выполнится на ура :)
То же самое можете проверить с любого компьютера с Windows в сети.
Комментарии, если есть предложения/пожелания - в форум. Если будет интересно, сваяю статью как ко всему этому хозяйству подступиться из Win для автоматического запуска скриптов/комманд.



размещено: 2007-04-24,
последнее обновление: 2007-04-24,
автор: Fastman

оценить статью:

fr33man, 2007-04-25 в 15:06:52

Не люблю C++... Лучше C.

IMHO.

Fastman, 2007-04-25 в 15:34:20

Эксперементировал. Можно и на С.

ALex_hha, 2007-04-26 в 18:26:28

Нее, уж лучше на ассемблере

Dushes, 2007-04-27 в 18:51:41

ОГРОМНОЕ спасибо автору давно уже ищу что нить подобное ...

Dushes, 2007-04-27 в 18:55:13

А вообще примеры с коментариями по програмированию очень актуально ...

Fastman, 2007-04-27 в 19:01:54

Народ, давайте в форум если есть вопросы, попробую ответить, дам комментарии, сам учусь, и будет приятно опытом поделиться.

un, 2007-05-04 в 21:52:44

Ждем того же, но под Win :)

dehun, 2007-05-04 в 23:32:16

А после того как клиент закрывает соединение и процесс умирает он в зомби не преврашяется( Ну всмысле чтобы хранить код завершения ) ?

На асме не кроссплатформенно =)

Под винду насколько знаю не форкаются, а создают новый поток просто. Практически тоже самое вобшемто в плане кода.

Fastman, 2007-05-04 в 23:43:21

dehun
Обращаем внимание на
void tcpdaemon::sighandler(int signum)
{
   waitpid(0, 0, WNOHANG);
}

и
memset(&sa, 0, sizeof(sa));
sa.sa_handler = &sighandler;
sigaction(SIGCHLD, &sa, 0);

Под винду насколько знаю не форкаются, а создают новый поток просто. Практически тоже самое вобшемто в плане кода.

Процесс и поток - разные вещи.

Сервер выкладывать под винду не буду, тут FreeBSD :)
А вот про клиента и под Win и под FreeBSD - напишу.
Быстро не обещаю, работы много, но постараюсь.
И вообще потестил бы кто нить. Никто не сказал, что в принципе все что было написано выше работает гарантированно только под root-ом :)

ALex_hha, 2007-05-12 в 12:36:50

Не очень понял смысл этой программы, а чем вас ssh не устраивает?

ALex_hha, 2007-05-12 в 16:17:58

хм....
из клиента написанного под Windows запускать скрипты на Unix машине

Если ты мне расскажешь как использую ssh написать на C++ в VS8 примерно следующий функционал: клиент должен запускать 2-5 процессов одновременно на сервере (путем запуска обычного sh скрипта) которые могут работать в течении от 20мин до 3часов. При этом нужно иметь обратную связь с сервером(знать запустился процесс на выполнение или нет, завершился корректно или нет, с какими ошибками и.т.д. и.т.п.)
То я буду оч благодарен. Не шучу. Пиши статью в раздел.

миро, 2007-06-01 в 12:24:47

system не выполняет команд внутри этого tcpdaemon класса

           int i  = system(cmd.c_str());
       if(i == -1)
       {
       answer = "err";
       }
       else answer = "ok";

Уберите две "щщ" в слове Товарищщи!, 2007-07-29 в 12:47:50

БЛЯ

тормоз?, 2007-10-25 в 4:15:13

ssh -ladmin server /bin/sh

> клиент должен запускать 2-5 процессов одновременно на сервере
> (путем запуска обычного sh скрипта) которые могут работать
> в течении от 20мин до 3часов.

ssh -ladmin server /bin/ls
ssh -ladmin server /bin/ps
ssh -ladmin server /bin/df

> При этом нужно иметь обратную связь с сервером
> (знать запустился процесс на выполнение или нет, завершился
>  корректно или нет, с какими ошибками и.т.д. и.т.п.)

читать вывод, парсить ошибки.

Fastman, 2007-10-29 в 23:33:27

тормоз?
Блин... вы интересные ананимусы.... и что ты понаписывал то ? Мне вместе с клиентским софтом отдельно таскать ssh клиент ? или пихать в софт класс для работы с ssh в свое приложение? Это несерьезное решение. Это не пригодно для меня.
...
как использую ssh написать на C++ в VS8
читаем и понимаем.. что ничего конкретного не написано. Xоть в статью оформи хоть в форум напиши. Запускай через свой ssh mencoder и пускай он DV файло в mpeg4 жмет. Дает отчет о живучести о проценте выполнения и пускай лог пишет. Мне проще написать свое приложение пускай с нуля... пускай сначало коряво (оттещу научусь и доделаю) чем использовать нечто похожее на костыли.

tolik, 2008-06-04 в 16:35:37

Вообще-то, для таких целей есть inetd...

анонимус такой с претензией, 2008-08-20 в 21:27:55

для кого статья не ясно...
т.к. если человек знает что такое сокеты, ему эта статья не нужна. а для тех кто не знает(такие как я 2 часа назад) - смысл пялится на непонятные строчки?? или люди сами поняли что обозначает каждая строчка? я не верю что я здесь один такой тупой.
http://www.linuxhowtos.org/C_C++/socket.htm - первая ссылка в гугле и то лучше.

Seltsam, 2008-12-12 в 9:12:58

to анонимус такой с претензией : если тебе это не понятно, то и не читай! кому надо - тот знает! а впервые узнавать о сокетах и т.п. надо не из таких статей!
Извини за прямоту...
Интересующимся - есть вариант на Perl для TCP- и UDP- серверов, может кому будет и проще и интересней.
Автору - думаю можно использовать для таких целей UDP-сервер, в этом случае нет необходимости думать о форках и т.д.
В качестве клиента для винды можно написать простую формочку на C++ Builder, там есть компоненты для такой работы.
Сам давеча написал демон под UDP, который принимает инфу от виндовых клиентов при входе логоне/логофе юзера в систему и складывает всё это в БД MySQL. Ну а далее уж от фантазии зависит что делать с этой БД =)

v01d.cmd, 2009-01-07 в 10:07:09

Cпс за статью. Проверил на Mac OS X 10.5 пашет, подлюбым пользователем кроме Guest. Привелегии почти по умолчанию.

Тем кто в танке: статья образовательная, для нубов и скрипткидов. Понимаю что ssh надежней... напиши статью про это, все скажут СПС тебе, в т.ч. я =).

Dis, 2009-04-23 в 18:33:38

Спасибо за статью, помогла, правда писал на Си.

alky, 2009-10-03 в 2:55:03

>Блин... вы интересные ананимусы.... и что ты >понаписывал то ? Мне вместе с клиентским софтом >отдельно таскать ssh клиент ? или пихать в софт класс >для работы с ssh в свое приложение? Это несерьезное >решение. Это не пригодно для меня.
>...

ссш по любому лучше. цель выполнить команды удаленно? он для этого и создан и к тому же безопасен.
а почему бы не таскать если это УЖЕ ГОТОВО?
или если интегрировать - www.libssh.org..
ЭТО ЖЕ ОСНОВНОЙ ПРИНЦИП ОПЕН СОРС - не строить велосипеды..
ну а если про сокеты... нет ни одного коммента к коду!(типа кто-то врубился во все. ага щас.)
http://www.linuxhowtos.org/C_C++/socket.htm  - тут реально разжевано, спасибо анониму за ссылку.

Olorin, 2010-02-10 в 17:50:35

Рекомендую: opennet.ru

ostrik, 2011-02-24 в 18:08:39

Хорошо бы еще упомянуть настоящего автора этого кода :)
http://konst.org.ua/ru/writings
http://www.codenet.ru/progr/cpp/demons.php

Не хорошо выдавать чужое за свое.

ivan, 2011-07-19 в 9:48:52

Трабл.
Открываем телнетом два конекта к сокету и выполняем команду (к примеру ls) - результат выполнетия из обеих сесий выводится на первую. При этом результат выполнения внутреней комманды (к примеру version) выводится в ту сесию с которой выполнял.

pinger, 2011-12-27 в 12:06:25

Под виндой в Cygwin собирается и работает, если закомментить строки с методами memset() и exit().
Спасибо!

Cpp_dev, 2013-10-21 в 11:12:19

Даже сейчас статья оказалась полезной. Нигде не нашел небольшего, но понятного кода, чтоб во всем разобраться, повезло только здесь. Теперь немного разбрался с тем, как создать демона. Большое спасибо за статью!
Конечно коменты в коде были бы не лишни)

Cpp_dev, 2013-10-21 в 16:03:49

Можно еще заменить system() на popen(), чтобы вместо ок и err возвращать результаты команды, что очень удобно.

Den, 2013-12-14 в 14:32:17

Статья полезна только в качестве примера для программирования. Практического применения ей нет. Автоматизацию даёт cron (уж точно не ручной запуск скриптов:), а удаленное подключение через ssh куда более удобно (из под win в тч). Автор, видимо, в первый раз FreeBSD увидел )))). На момент написания статьи был еще совсем зеленым )))

aa, 2015-07-09 в 23:32:33

Не компилится...
sh ./make.sh
tcp_daemon.cpp: In member function ‘void tcpdaemon::daemonize()’:
tcp_daemon.cpp:53:31: error: ‘memset’ was not declared in this scope
     memset(&sa, 0, sizeof(sa));
                              ^
tcp_daemon.cpp:61:12: error: ‘exit’ was not declared in this scope
     exit(0);
           ^
tcp_daemon.cpp: In member function ‘void tcpdaemon::mainloop()’:
tcp_daemon.cpp:83:27: error: ‘memset’ was not declared in this scope
 memset(&sa, 0, sizeof(sa));
                          ^
tcp_daemon.cpp: In member function ‘void tcpdaemon::operate(int)’:
tcp_daemon.cpp:171:11: error: ‘exit’ was not declared in this scope
    exit(0);
          ^


Оставьте свой комментарий:
Ваше имя:   *
e-mail:  
жирный
наклонный
подчёркнутый
ссылка
цвет
Нынешний год:   *
 


Хостинг HOST-FOOD

2014-07-27, lissyara
gmirror

Удалённое создание софтверного зеркала средствами gmirror, на диске разбитом с использованием gpart. Использование меток дисков для монтирования разделов.
2013-08-20, zentarim
Scan+Print server FreeBSD 9

Настройка сервера печати и сервера сканирования под управлением операционной системы FreebSD 9 для МФУ Canon PIXMA MP540
2011-11-20, BlackCat
Разъём на WiFi-карту

Делаем съёмной несъёмную антену на WiFi-карте путём установки ВЧ-разъёма
2011-09-14, manefesto
Настройка git+gitosis

Настройка системы контроля версия исходного кода в связке git+gitosis+ssh
2011-08-14, zentarim
Wi-FI роутер + DHCP + DNS

Настройка Wi-Fi роутера на Freebsd 8 + DNS сервер + DHCP сервер: чтобы Wi-Fi клиенты были в одной подсети с проводными, проводные и беспроводные клиенты получали адреса автоматически по DHCP, кэширующ
2011-06-15, -ZG-
Охранная система на FreeBSD+LPT

В этой статье описана попытка реализации простой охранной системы на базе FreeBSD с подключением к ней охранных устройтсв на LPT порт и видеорегистрацией.
2011-03-13, terminus
ng_nat

Описание работы ng_nat, практическое использование, достоинства и недостатки в сравнении с ipfw nat
2011-02-20, Капитан
Nagios+Digitemp

Статья описывает создание системы оповещения о превышении температуры в специальных помещениях на основе Nagios с использованием программы Digitemp.
2011-02-17, Le1
Zyxel Configuration

Скрипт для массового изменения конфига свичей Zyxel. Берет из файла iplist список ip-шек, заходит последовательно на каждый и выполняет комманды из файла commands, записывая происходящее в лог файл.
2011-02-16, fox
hast carp zfs ucarp cluster

HAST (Highly Available Storage), CARP, UCARP, ZFS, Cluster настройка и одаптация плюс личные размышления…
2011-02-04, BlackCat
Восстановление ZFS

История о том, как был восстановлен развалившийся RAIDZ ZFS-пул (перешедший в FAULTED) с помощью скотча и подручных средств. Или о том, какие приключения ожидают тех, кто не делает резервных копий.
2011-02-03, Капитан
1-Wire

Статья описывает самостоятельное изготовление контроллера DS9097 для съёма показаний с датчиков температуры DS1820 с помощью программы Digitemp.
2011-01-28, Капитан
Температура в серверной

Статья описывает построение системы наблюдения за температурой в помещении серверной с использованием программы Digitemp и выводом графиков в MRTG
2011-01-21, m4rkell
Syslog server

Как то буквально на днях, у нас завалилось, что то в еве) или не в еве не суть. Суть в том, что когда захотели снять логи с хостов esx обнаружили, что хранят эти негодяи логии только за последнии сутк
2011-01-07, lissyara
Canon/gphotofs

Монтирование цифровых фотоаппаратов Canon (PTP) как файловой системы, автоматизация этого процесса через события devd и внешние скрипты.
2010-12-13, Al
IPSec

Описание принципов работы IPSEC и способов аутентификации.
2010-12-07, manefesto
FreeBSD on flash

Было принято решении переехать на USB Flash и установить минимальный джентельменский набор для работы своего роутера. Делаем =)
2010-12-05, Fomalhaut
root ZFS, GPT

Инструкция по установке FreeBSD с использованием в качестве таблицы разделов GPT и в качестве основной файловой системы - ZFS
2010-09-05, Cancer
Настройка аудиоплеера на ximp3

Цели: Простенький аудиоплеер, для того что бы тетя продавец в магазине утром пришла нажала на кнопку Power и заиграла в зале музыка, так же был доступ по сети, общая шара куда можно заливать музыку, к
2010-08-31, Cancer
Установка и настройка OpenVPN

На днях появилась задача - объединить головной офис и 3 филиала в одну сеть через интернет посредством OpenVPN, чтобы люди могли подключаться через RDP к базам 1С на серверах.
2010-08-25, manefesto
freebsd lvm

Использование linux_lvm для работы с LVM разделами из-под FreeBSD. Проблемы которые возники при монтирование lvm раздела
2010-04-30, gonzo111
proftpd file auth&quota

Proftpd - квоты и авторизация из файлов, без использования базы данных и/или системных пользователей
2010-04-22, lissyara
tw_cli

Пошаговая инструкция по восстановлению RAID на контроллере 3ware, из которого выпал один диск. Настройка мониторинга состояния рейда и отчётов о его состоянии на email.
2010-04-14, fox
MySQL Master+Master

MySQL (Master Master) and (Master Slave) Как настроить репликацию…
2010-03-09, terminus
DNS zones

Краткий ликбез про управление DNS зонами. Примеры проведения делегирования прямых и обратных DNS зон.
2010-03-09, aspera
Squid+AD (group access)

Настройка прокси сервера SQUID с автроризацией пользователей в AD. Разделение пользователей на группы
2010-03-02, BlackCat
Шлюз: Часть 4

Настройка дополнительных сервисов: синхронизация времени (OpenNTPD), клиент DynDNS.org.
2010-03-01, BlackCat
Шлюз: Часть 3

Настройка DHCP и DNS серверов для работы внутри частной сети, c поддержкой внутренних (частных зон) DNS, а так же интеграция DHCP и DNS сервисов.
2010-03-01, BlackCat
Шлюз: Часть 2

Конфигурация МСЭ pf для проброса портов с изменением порта назначения и без, а так же поддержки активного режима FTP и ограничения максимального размера сегмента
подписка

    вверх      
Статистика сайта
Сейчас на сайте находится: 22 чел.
За последние 30 мин было: 113 человек
За сегодня было
5436 показов,
1283 уникальных IP
 

  Этот информационный блок появился по той простой причине, что многие считают нормальным, брать чужую информацию не уведомляя автора (что не так страшно), и не оставляя линк на оригинал и автора — что более существенно. Я не против распространения информации — только за. Только условие простое — извольте подписывать автора, и оставлять линк на оригинальную страницу в виде прямой, активной, нескриптовой, незакрытой от индексирования, и не запрещенной для следования роботов ссылки.
  Если соизволите поставить автора в известность — то вообще почёт вам и уважение.

© lissyara 2006-10-24 08:47 MSK

Время генерации страницы 0.0496 секунд
Из них PHP: 33%; SQL: 67%; Число SQL-запросов: 77 шт.
Исходный размер: 108531; Сжатая: 22779