LINUX.ORG.RU

Как определить что отвалился клиент от сервера ? (C++/daemon)


0

0

#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("mencoder_server", 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 = "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 = "ierr";
        }
        else if (i !=0 )
        {
        
         answer = "fld";
        }
       
        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;
}

Нужно сгененировать сообщение при отваливании клиента.

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

man 2 read
+ раздел соотв. разделы в info 

MKuznetsov ★★★★★ ()

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

http://www.linux.org.ru/books/man/man/man2/read.2.html
 |
\_/
Пусто кстати.
Если можно, пару предложений, о принципе
сего действа )

Fastman ()

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

Смотря что понимать под отвалился. Если клиент закрыл сокет, то read прочитает 0 байт. Если на той стороне выдернули сетевой кабель или на файрволе сказали DROP, то имхо по таймауту только. Ну или средствами ОС/прикладной программы отправлять keep-alive пакеты, хотя тут тоже все к таймауту сводится.

anonymous ()

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

heartbeat на внеполосных данных TCP сессии. Подробности у Стивенса.

jr_A ()

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

общее решение - только по таймауту...

vilfred ☆☆ ()

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

Ну как по таймауту !!! Keepalive по умолчанию в FreeBSD
по мойму 2 часа(через sysctl не предлагать устанавливать)! 
А нужно убивать соединение через 10 сек.

Fastman ()

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

и еще вот эта строчка

int i = system(cmd.c_str());

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

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

Fastman ()

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

а больше никак, кроме таймаута. реально, ситуация сводится к выдергиванию сетевого кабеля из сетевухи. Мало ли где на маршруте соединения (то, что показывается на выводе traceroute) произошел обрыв или изменился маршрут соединения. Никак это не отловить. Насколько я понимаю, TCP подтверждает доставку пакета. А если канал связи оборван то и подтверждения нет.

vilfred ☆☆ ()

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

> А нужно убивать соединение через 10 сек.

Как я бы сделал. если предел 10 секунд, раз в 3 секунды с клиента слал бы чтонибудь. Если сервер более чем 8 секунд не получает сообщения, значит связь разорвана.

vilfred ☆☆ ()

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

правдадля этой оработки "раз в 10 секунд" надо еще 5 килобайт кода писать но тут, ихо. ничего не сделаешь, добро пожаловать в реальность...

vilfred ☆☆ ()

Re: Как определить что отвалился клиент от сервера ? (C++/daemon)

Так оно и оказалось... Пришлось запускать параллельно
с запуском функции которая скрипт запускает процесс который
мониторит по дескриптору сокета его состояние....
Хм.. не верю что нет стандартных вещей для таких случев....

Fastman ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.