Как поднять упавшее соединение по unix domain socket?

Доброго времени суток.
Есть 2 программы, соединяющиеся по юниксовым сокетам. Одно приложение выступает в качестве сервера, другое в качестве клиента. Делаю попытку восстановления соединения на клиенте. То есть если внезапно падает сервер, то раз в сколько-то секунд клиент должен попытаться подключиться.
Теперь код. Создание сокета create():
spoiler
::bzero(&_sock, sizeof(_sock)); // _sock имеет тип sockaddr_un
_sock.sun_family = AF_UNIX;
strncpy(_sock.sun_path, socket_name, sizeof(_sock.sun_path) - 1);
_sdSocket = ::socket(AF_UNIX, SOCK_STREAM, 0); // _sdSocket - int
if ( _sdSocket < 0 ) {
    showError("Create socket failed. errno: " + std::to_string(errno));
    return false;
}
if ( !makeSocketNonBlocking(_sdSocket) ) return false;
if ( !createEpoll() ) return false;
return true;

Функция connect
spoiler
int len = strlen(_sock.sun_path) + sizeof(_sock.sun_family);
if ( ::connect(_sdSocket, (struct sockaddr *)&_sock, len) < 0 ) {
    showError("Connect socket failed. Errno: " + std::to_string(errno));
    return false;
} else {
    showInfo("connected to Transceiver");      
    event.data.fd = _sdSocket;
    event.events = EPOLLIN | EPOLLET;
    if ( ::epoll_ctl(_sdEpoll, EPOLL_CTL_ADD, _sdSocket, &event) < 0 ) {
        if ( _sdEpoll < 0 ) {
            showError("epoll_ctl failed");
            return false;
        }
    }
}
return true;

Кусок функции приема пакета, которая отвечает за закрытие сокета
spoiler
sizeHdr = ::recv(_sdSocket, &buf, sizeof(struct messaging::HugeMessage), 0);
if ( sizeHdr == 0 ) {
        ::close(_sdSocket);
        showInfo("Socket closed");
        _connected = false;
}

Т.к. помимо работы с сокетом есть еще задачи для программы, сделал через вечный цикл опрос epoll'a, выглядит так:
spoiler
if ( _connected == false) {
    //if ( create() ) {
        showInfo("Trying connected...");
        _connected = connect();
    //}
    return;
}

int n = epoll_wait(_sdEpoll, arrEvents.data(), countConnect, 0);
if ( n == 0 ) return;
if ( n < 0 ) {
    showError("epoll wait");
    return;
}
for ( int i{0}; i < n; i++ ) {
    if ( arrEvents[i].events & EPOLLERR ||
         arrEvents[i].events & EPOLLHUP ||
         !(arrEvents[i].events & EPOLLIN) ) {
            showError("epoll event error. Errno: " + std::to_string(errno));
            if ( _sdSocket == arrEvents[i].data.fd ) {
                ::close(_sdSocket);
                _connected = false;
            }
        } else {
            receiver();
        }
    }

Вот в последней функции, сначала идет проверка "А есть ли соединение?" и если нет, то пытаемся подключиться. Так вот, если связь была, и сервер упал, то я ловлю это событие, закрываю сокет. На следующей итерации попытка подключиться. И всегда возвращает false. Решил только через костыль (как я считаю), после закрытия сокета, он полностью очищается и по новой вызывается функция ::socket, ::connect и т.д. и вот так работает. Подскажите, пожалуйста, как мне не пересоздавать сокеты, но восстанавливать соединение?
  • Вопрос задан
  • 386 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы