现实环境中,当应用程序收到Ctrl-C或其他诸如ETERM的信号时需要能够正确地清理和退出。默认情况下,这一信号会杀掉进程,意味着尚未发送的消息就此丢失,文件不能被正确地关闭等。
在C语言中我们是这样处理消息的:
interrupt: Handling Ctrl-C cleanly in C
发布者代码:
//
// Shows how to handle Ctrl-C
//
// ---------------------------------------------------------------------
// 消息处理
//
// 程序开始运行时调用s_catch_signals()函数;
// 在循环中判断s_interrupted是否为1,是则跳出循环;
static int interrupted = 0;
void signal_handler (int sig)
{
(void)sig;
interrupted = 1;
}
void catch_signals (void)
{
struct sigaction action;
action.sa_handler = signal_handler;
action.sa_flags = 0;
sigemptyset (&action.sa_mask);
sigaction (SIGINT, &action, NULL);
}
int main (void)
{
void *context = zmq_init (1);
void *publisher = zmq_socket (context, ZMQ_PUB);
zmq_bind (publisher, "tcp://*:5555");
catch_signals ();
char buf[256];
int i = 0;
while (!interrupted)
{
sprintf(buf, "helloworld%d", i++);
zmq_send (publisher, buf, strlen(buf), 0);
sleep(1);
}
zmq_close (publisher);
zmq_term (context);
return 0;
}
订阅者代码:
static int interrupted = 0;
void signal_handler (int sig)
{
(void)sig;
interrupted = 1;
}
void catch_signals (void)
{
struct sigaction action;
action.sa_handler = signal_handler;
action.sa_flags = 0;
sigemptyset (&action.sa_mask);
sigaction (SIGINT, &action, NULL);
}
void dump_msg(const void * data, int size)
{
unsigned char * ptr = (unsigned char *)data;
printf ("[%03d] ", size);
int i = 0;
for (i = 0; i < size; i++)
printf ("%02X", ptr[i]);
printf ("\n");
}
int main (void)
{
catch_signals();
void *context = zmq_ctx_new();
void *subscriber = zmq_socket (context, ZMQ_SUB);
/*订阅所有的内容*/
zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0);
zmq_connect (subscriber, "tcp://127.0.0.1:5555");
while (!interrupted)
{
char buf[256];
int ret = zmq_recv (subscriber, buf, sizeof(buf) - 1, 0);
if(ret == -1)
perror("zmq_recv");
buf[ret] = '\0';
printf ("recv msg %s\n", buf);
}
// 程序不会运行到这里,以下只是演示我们应该如何结束
zmq_close (subscriber);
zmq_ctx_destroy(context);
return 0;
}
需要注意的是zmq_recv,zmq_msg_recv等函数都会被信号打断,返回-1,并且设置errno为EINTR。