ZeroMq路由器静默丢弃消息

时间:2013-11-22 15:21:55

标签: messaging zeromq jeromq

我有一个服务器(ROUTER套接字)绑定并允许单个客户端(DEALER套接字)连接到它。然后服务器开始发送数据。

理想情况下,我想知道路由器何时达到其hwm设置并开始丢弃消息。我在路由器上将ZMQ_ROUTER_MANDATORY设置为1,但这也无济于事。路由器继续报告消息是发送的,即使我没有启动客户端(isAlive = false,所以没有什么可以在另一端拉这些消息)。

我做错了什么,或者在ROUTER套接字上HWM设置是不可靠的?

我在Windows 7 64位上使用jerk版本0.3.1和jdk 1.6.0_32

由于

public final class SenderSocket implements Runnable{

    private final int total;
    private final int sentHwm;
    private final String address;
    private final Socket sendSocket;
    private final ExecutorService executor;

    private final static String NAME        = SenderSocket.class.getSimpleName( );
    private final static Logger LOGGER      = LoggerFactory.getLogger( NAME );


    public SenderSocket( ZContext context, String address, int sentHwm, int total ){
        this.address        = address;
        this.total          = total;
        this.sentHwm        = sentHwm;
        this.sendSocket     = context.createSocket( ZMQ.ROUTER );
        this.executor       = Executors.newSingleThreadExecutor( );
    }


    public void init( ){

        sendSocket.setSndHWM( sentHwm );
        sendSocket.setRouterMandatory( true );
        sendSocket.bind( address );

        executor.execute( this );
        LOGGER.info("ROUTER configured with HWM {} bound to {}.", sentHwm, address );

    }



    @Override
    public void run( ){         

        for( int i =0; i <total; i++ ){      

            try{

                String item     = new StringBuilder(8).append(i).toString();
                boolean result  = sendSocket.send( item );

                LOGGER.info("SENT>> [{}] [{}]", result, item );

            }catch( ZMQException zmqEx ){

                int errorCode = zmqEx.getErrorCode();

                if( ZError.EHOSTUNREACH == errorCode ){
                    LOGGER.warn("Attempted to send message to but dealer is DOWN!");
                }

                if( ZMQ.Error.ETERM.getCode() == errorCode ){
                    LOGGER.error("Received error code [{}], terminating.");
                    stop();
                }

                LOGGER.error("ZMQException while sending message.", zmqEx);

            }catch( Exception ex ){
                LOGGER.error("Exception while sending message.", ex );
            }

        }

        stop();

    }


    public void stop( ){
        sendSocket.setLinger( 0 );
    }


}

// CLIENT

    public class ReceiverSocket implements Runnable{

        private final int hwm;
        private final String address;
        private final Socket recvSocket;
        private final ExecutorService executor;

        private volatile boolean isAlive;

        private final static String NAME        = ReceiverSocket.class.getSimpleName( );
        private final static Logger LOGGER      = LoggerFactory.getLogger( NAME );


        public ReceiverSocket( ZContext context, String address, int hwm ){
            this.address        = address;
            this.hwm            = hwm;
            this.recvSocket     = context.createSocket( ZMQ.DEALER );
            this.executor       = Executors.newSingleThreadExecutor( );
        }


        public void init( ){

            this.isAlive = false;

            recvSocket.setRcvHWM( hwm );
            recvSocket.connect( address );
            executor.execute( this );

            LOGGER.info("DEALER configured with HWM {} connected to {}.", hwm, address );

        }



        @Override
        public void run( ){         

            Poller poller       = new Poller( 1 );
            poller.register( recvSocket, Poller.POLLIN );

            while(  isAlive ){      

                try{

                    int pollCount       = poller.poll( );

                    if( pollCount == NEGATIVE_ONE ){
                        LOGGER.warn("ERROR! Was the thread interrupted?", pollCount );
                        isAlive = false;
                        return;
                    }

                    if( poller.pollin( ZERO ) ){
                        String data = recvSocket.recvStr( );
                        LOGGER.info("RECVD >> {} {}", data, NEWLINE );
                    }

                }catch( Exception e ){
                    LOGGER.error("Exception while receving message.", e);
                }

            }

        }


        public void stop( ){
            recvSocket.setLinger( 0 );
            LOGGER.info("{} Stopped!", NAME );
        }
}

// MAIN

public static void main( String[ ] args ) throws InterruptedException{

        int recvHwm          = 5;
        int sentHwm          = 5;
        int totalSent        = 5000;
        String address       = "tcp://*:20000";
        ZContext context     = new ZContext( 1 );

        ReceiverSocket recvr = new ReceiverSocket( context, address, recvHwm );
        SenderSocket sender  = new SenderSocket( context, address, sentHwm, totalSent );

        recvr.init();
        Thread.sleep( 1000 );

        sender.init();

    }

2 个答案:

答案 0 :(得分:3)

路由器强制和高水位标记彼此无关。

  

我已经在路由器上将ZMQ_ROUTER_MANDATORY设置为1但是   也没有帮助。路由器继续报告该消息   即使我没有启动客户端

也被发送

即使没有对等方连接到路由器,路由器也不会引发异常,除非您针对特定客户端ID解决该消息。

//#1 no exception raised here, message dropped silently
rtr.setRouterMandatory(true)
rtr.bind("tcp://*:20000")
rtr.send("omg!")

//#2 exception raised here
rtr.setRouterMandatory(true)
rtr.bind("tcp://*:20000")
rtr.sendMore("client1")
rtr.sendMore("")
rtr.send("omg!")

代码示例#2抛出异常,因为您告诉路由器将“omg”发送给具有标识client1的对等方。路由器套接字通过为每个连接的对等体分配随机标识来跟踪所有连接。如果路由器没有client1的连接,或者,如果先前已断开client1,路由器将在两种情况下都引发异常。

您可以在客户端上分配标识以覆盖路由器随机标识分配:

client.setIdentity("client1".getBytes())
client.connect("tcp://*:20000")

上面的代码阻止路由器套接字在样本#2中引发异常

我建议阅读this,它解释了信息寻址和包络;了解它的工作原理对于使用路由器套接字至关重要。

答案 1 :(得分:0)

在python中,这使路由器在这种情况下提升zmq.Again:

    self.context = zmq.Context()
    self.socket = self.context.socket(zmq.ROUTER)

    # make sure router doesn't just drop unroutable message
    self.socket.setsockopt(zmq.ROUTER_MANDATORY, 1)

    # make sure when there is unroutable message to raise exception after timeout
    timeout_sec = 2.5
    timeout_milisec = int(timeout_sec * 1000)
    self.socket.setsockopt(zmq.SNDTIMEO, timeout_milisec)

请参阅http://grokbase.com/t/zeromq/zeromq-dev/12aje3ya9t/zmq-router-mandatory-was-zmq-router-behavior