V
V
Vitaly Azovsky2017-04-13 13:05:17
linux
Vitaly Azovsky, 2017-04-13 13:05:17

How to raise a dropped connection on a unix domain socket?

Good day.
There are 2 programs connecting via Unix sockets. One application acts as a server, the other as a client. I'm trying to restore the connection on the client. That is, if the server suddenly crashes, then every few seconds the client should try to connect.
Now the code. Create socket 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 function
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;

A piece of the packet receiving function that is responsible for closing the socket
spoiler
sizeHdr = ::recv(_sdSocket, &buf, sizeof(struct messaging::HugeMessage), 0);
if ( sizeHdr == 0 ) {
        ::close(_sdSocket);
        showInfo("Socket closed");
        _connected = false;
}

Because in addition to working with the socket, there are still tasks for the program, I made an epoll poll through an eternal loop, it looks like this:
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();
        }
    }

Here in the last function, first there is a check "Is there a connection?" and if not, then we try to connect. So, if there was a connection, and the server fell, then I catch this event, close the socket. On the next iteration attempt to connect. And it always returns false. I decided only through a crutch (as I think), after the socket is closed, it is completely cleared and the ::socket, ::connect, etc. function is called on a new one. and this is how it works. Tell me, please, how can I not recreate the sockets, but restore the connection?

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question