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;
}

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

Ответ на: комментарий от Fastman

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

anonymous
()

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

jr_A
()
Ответ на: комментарий от vilfred

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

Fastman
() автор топика
Ответ на: комментарий от vilfred

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

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

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

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

Fastman
() автор топика
Ответ на: комментарий от Fastman

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

vilfred ☆☆
()
Ответ на: комментарий от Fastman

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

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

vilfred ☆☆
()
Ответ на: комментарий от vilfred

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

vilfred ☆☆
()
Ответ на: комментарий от vilfred

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

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