ZMQ连接的清理及其context部件的关闭

一开始使用jeroMQ,由于java会自动回收资源,所以socket对象及context对象的清理比较简单。断开连接和关闭连接不需要考虑连接的状态。所以程序比较简单。

但在C/C++环境下,zmq连接的处理需要考虑如下情况:

(1)在zmq_recv()的阻塞状态下,不可能断开连接。

(2)在连接没有断开和关闭的情况下,context不能关闭(呈阻塞状态)。

(3)在上面两种情况下,可能会有内存泄漏的问题。

为了解决以上问题,在C/C++环境下,必须:

(1)如果没有把握保证zmq_recv()一定能够接收到消息,则必须设置其ZMQ_RCVTIMEO值,使其在接不到消息时可以退出阻塞,以判断是否程序需要退出。

int recvTime = 500;
zmq_setsockopt(_socket, ZMQ_RCVTIMEO, &recvTime, sizeof(recvTime));
        ret1 = zmq_recv(_zsocket, sub, 128, 0);
        //接收消息
        if(ret1 == -1)
        {
            int error = zmq_errno();
            cout << "ERROR: messageReceiver socket: wrong message --" << zmq_strerror(error) << endl;
            if(getSimEnd())
            {
                //closedeliver(); //stop deliver
                closeCallbackLink(); //stop the callback link
                cout << "messageReceiver thread closed......2" << endl;
                return;
            }
        }
void MessageReceiver::closeCallbackLink()
{
    //QMutexLocker locker(&_mutex);
    if(_zsocket == nullptr)
        return;
    //setSimEnd();
    //Sleep(500);
    if(_type == tcp)
    {
        char abuf[128];
        memset(abuf, '', 128*sizeof(char));
        sprintf_s(abuf, 128*sizeof(char), "tcp://%s:%d", _rtiHost.c_str(), fport);
        zmq_disconnect(this->_zsocket, abuf);
        zmq_close(_zsocket);
        _zsocket = NULL;
        return;
    }
    if(_type == ipc)
    {
        char abuf[128];
        memset(abuf, '', 128*sizeof(char));
        sprintf_s(abuf, 128*sizeof(char), "ipc://%s", _rtiIpcAddress.c_str());
        zmq_disconnect(this->_zsocket, abuf);
        zmq_close(_zsocket);
        _zsocket = nullptr;
        return;
    }
}

(2)在退出阻塞时,要判定是否程序需要退出,如果不退出,则再调用zmq_recv()接收消息,如此循环。

(3)为了加快断开和关闭连接的速度,设置有限的ZMQ_LINGER值,使连接快速断开。

int linger = 0;
zmq_setsockopt(_socket, ZMQ_LINGER, &linger, sizeof(int64_t));

(4)在(1)中判定需要退出时,应当断开连接和关闭连接,释放socket。

(5)要想关闭context,必须关闭其上的所有socket,否则关闭context时会阻塞,导致程序无法退出。

(6)如果连接在线程内,则退出线程和关闭连接尽量同时完成。

在一个程序中,我在一个context上建立了两个连接,分别被两个线程使用,断开连接并关闭socket后,发现关闭context时总是阻塞,百思不得其解。后来偶然发现,在建立其中一个连接时,使用了zmq_socket_monitor建立了一个监视连接,这个sokcet也是建立在上面的context上的,豁然开朗。将该连接断开并将其socket关闭后,这个context被顺利关闭。

原文地址:https://www.cnblogs.com/myboat/p/14109942.html