admin管理员组

文章数量:1386653

If I have a server function that is listening to a port in an infinite loop, how do I stop it? If i do ctrl+c it terminates the process and the program does not get a chance to destroy the socket pointer. Whats the standard of dealing with this?

#include <czmq.h>

int main(int argc, char **argv){
    setvbuf(stdout, NULL, _IONBF, 0);
    zsock_t *responder = zsock_new(ZMQ_REP);
    int r = zsock_bind(responder, "tcp://localhost:5555");
    if (r != 5555){
        printf("Failed to bind\n");
    }
    while(true){
        char *msg = zstr_recv(responder);
        if (!strcmp(msg, "Bonjour!")){
            zstr_send(responder, "Ouais!");
        }
        free(msg);
        printf(".\n");
    }
    zsock_destroy(&responder);
}

If I have a server function that is listening to a port in an infinite loop, how do I stop it? If i do ctrl+c it terminates the process and the program does not get a chance to destroy the socket pointer. Whats the standard of dealing with this?

#include <czmq.h>

int main(int argc, char **argv){
    setvbuf(stdout, NULL, _IONBF, 0);
    zsock_t *responder = zsock_new(ZMQ_REP);
    int r = zsock_bind(responder, "tcp://localhost:5555");
    if (r != 5555){
        printf("Failed to bind\n");
    }
    while(true){
        char *msg = zstr_recv(responder);
        if (!strcmp(msg, "Bonjour!")){
            zstr_send(responder, "Ouais!");
        }
        free(msg);
        printf(".\n");
    }
    zsock_destroy(&responder);
}
Share Improve this question edited Mar 18 at 4:02 iam_ai_copy-paste 97412 silver badges38 bronze badges asked Mar 17 at 20:47 LabeebLabeeb 1077 bronze badges 7
  • any of: 0. design your program to be resilent to sudden shutdown regardless, 1. set a variable in the signal handler and catch the EINTR (buggy in some environments that blindly retry), 2. use the self-pipe trick, but beware overfull pipes, 3. use Linux-specific signalfd (easiest) – o11c Commented Mar 17 at 20:51
  • 7 If the program gets closed it will also close the associated file descriptors which includes sockets. There is no need to do this explicitly unless you want more than a socket close. – Steffen Ullrich Commented Mar 17 at 20:52
  • 1 zsys_handler_set – jxh Commented Mar 17 at 23:53
  • 1 No, it does not mean that zsock_destroy() will be called. It means that the underlying system socket will be closed, along with any other files that may be open, and that any and all dynamically-allocated memory held by the program will be freed. These are at least some of the things that zsock_destroy() would do if it were called. It might or might not be all of the things that function would do. – John Bollinger Commented Mar 18 at 3:30
  • 1 What the above comments are saying is that it's not a problem to terminate a program with open sockets under normal circumstances. If you're seeing a problem here, please spell out what you think the problem is and then we can address it. – Cubic Commented Mar 18 at 10:24
 |  Show 2 more comments

2 Answers 2

Reset to default 0

I have an answer that you may find useful, if you're using Linux.

In Linux, one can tap into process signals either by the traditional method of installing a signal handler, or by using signalfd. See this man page. This allows a process to set up which signals it wants to receive and handle, but have them delivered via a file descriptor instead of requiring a signal handler.

This is ideal in ZeroMQ based applications, because one can include the signal file descriptor in calls to functions like zmq_poll(). If a signal is delivered to the process, the signal fd becomes ready to read, and zmq_poll() returns saying so. One then reads data from the file descriptor, decide what it means and act accordingly.

The really nice thing is that you're handling the signal synchronously, in the context of the application's main thread (or whichever thread where you read the signal), rather than asynchronously in a handler routine. So there's no longer any limitations on what functions one can call whilst dealing with the signal. This way, signal arrival becomes just another source of events that zmq_poll() can notify the program about.

It ends up being very slick. You can hit Ctrl-C, but the application won't get round to dealing with that until it's good and ready. For example, the program might pass on "quit" commands down a load of sockets to other processes, before itself terminates. That way a "Ctrl-C" in one process can readily propagate around an entire distributed system across a whole network. This is handy because if one has a bunch of processes written in different languages all cooperating via ZMQ, it can get messy installing signal handlers in all of those processes (which can be difficult in some high level languages).

Generally what I end up with in my systems built on ZMQ is that each process has a command/control socket, connected back to some master process. This is the one that I would interrupt with ctrl-c, and have it propagate "quit" commands to all the processes it is controlling.

Not on Linux? Well, I guess one could recreate this by having a signal handler as is conventional, and use that to cause some thread to write to a socket. That could be monitored in the way I've outlined above. This amounts to re-implementing signalfd for oneself. That's what Ian Abbott has linked to in his comment.

I will assume UNIX-like for this.

Use signal handlers. Include <signal.h> <stdlib.h> for the definitions.

The Ctrl+C is a KeyboardInterrupt, which in emits the SIGINT signal to the process currently running in the terminal window to stop. Normally, the process would just terminate in error state (1), but if you register a signal handler for SIGINT, you can make it do something before ending in normal state (0).

You have to register a handler to handle a signal in the thread you want to capture it, so for example, a simple registering in the main thread would look like this:

int main(){
    struct sigaction sa;
    sa.sa_handler = my_handler;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }
    return 0;
}


//you also have to implement the handler function you just mapped to SIGINT
void my_handler(int sig) {
    printf("Aborting gracefully...\n");
    freeResources(); //This could take care of closing sockets or whatever you need to do before exiting
    exit(0);
}

本文标签: cHow to gracefully terminate a socket serverStack Overflow