ZeroMQ(java)Socket之Req

前面的一篇文章分析了Dealer类型的Socket,它的行为是非常简单的,

它会维护一个链表,在链表的前面是当前活动的pipe,因为pipe连接的是下面的Session,那么活动的pipe也就意味着活动的StreamEngine,那么也就意味着活动的连接,

对于执行send方法,也非常的简单,就是在活动的pipe部分,通过循环的方式,选出一个pipe,将数据写进去就好了,因为可以看成是循环的遍历,所以对于数据的发送,这里也可以理解为比较简单额负载均衡了。。

这里要分析Req类型的Socket,它直接继承自Dealer类型的Socket,所以其实它的行为与Dealer类型的Socket的行为非常的类似,但是对有一个最为不一样的地方:

每一次通信,Req类型的Socket都必须按照send,recv的顺序来执行,首先执行send方法,将request发送出去,然后再执行recv方法接收返回的数据,这里顺序还不能出错。。。。

那么其实也就简化了数据的通信,强制要求同一时刻只能通过一个StreamEngine来收发数据。。。

首先来看看Req定义的两个重要的属性:

    private boolean receiving_reply;  //标志位,如果是ture的话,表示request已经发送了,正在等待reponse
    private boolean message_begins;   //如果是true的话,那么表示这里还需要发送第一个标志的空msg

首先是receiving_reply属性,如果它为true的话,那么表示request已经发送了, 接下来要执行recv,也就是接收返回的数据,如果返回数据还没有接收,就继续send的话,那么会报错。。。

message_begins属性,每一次发送首先都会发送一个空的msg,当做标志,每一接收返回,都会首先接收一个空的msg标志,用这个标志位来表示这个空的msg是否已经发送或者接收。。。

接下来来看看在Req中定义的send和recv方法吧:

    //在socketBase终将会具体的调用这个方法来发送数据,其实是通过pipe将数据发到Session端
    public boolean xsend(Msg msg_)
    {
    	//如果已经发送了数据而且在等待返回,这个时候不能连续发送数据
        if (receiving_reply) {
            throw new IllegalStateException("Cannot send another request");
        }

        //  First part of the request is the request identity.
        if (message_begins) {  //先发送一个空的标志message
            Msg bottom = new Msg();
            bottom.set_flags(Msg.more);  //表示在这个msg后面还有msg接着要发送
            boolean rc = super.xsend(bottom);  //调用dealer的方法来具体的发送数据
            if (!rc) { //第一个标志message发送失败
                return rc;
            }
            message_begins = false;  //将标志位设置为false,用于表示最开的空的msg已经发送了
        }

        boolean more = msg_.has_more();  //获取more标志位用于判断当前要发送的msg后面是否还有接着的msg要发送

        boolean rc = super.xsend(msg_);  //还是调用父类的方法发送数据
        if (!rc)
            return rc;

        //  If the request was fully sent, flip the FSM into reply-receiving state.
        if (!more) {
            receiving_reply = true;  //这里表示一个reqeust已经发送了,需要等待返回的response
            message_begins = true;   //将标志位从新设置为true,这里more标志位已经没有了,那么表示request的send过程已经完成,那么接下来的recv过程首先也需要接收一个空的msg
        }

        return true;
    }

    @Override
    //接收数据的方法
    protected Msg xrecv()
    {
        //  If request wasn't send, we can't wait for reply.
        if (!receiving_reply) {  //如果都没有发送request,那还接收response干啥
            throw new IllegalStateException("Cannot wait before send");
        }
        Msg msg_ = null;
        //  First part of the reply should be the original request ID.
        if (message_begins) {  //首先接收标志msg
            msg_ = super.xrecv();  //调用父类来接收msg
            if (msg_ == null)
                return null;

            // TODO: This should also close the connection with the peer!
            if ( !msg_.has_more() || msg_.size() != 0) {   //判断是否是标志msg,否则的话表示出错了
                while (true) {
                    msg_ = super.xrecv();
                    assert (msg_ != null);
                    if (!msg_.has_more())
                        break;
                }
                errno.set(ZError.EAGAIN);
                return null;
            }

            message_begins = false;   //将标志位设置为false,表示最开始用于标识的空的msg已经接受了
        }
        //标志msg接收完了之后再接收其余的msg
        msg_ = super.xrecv();
        if (msg_ == null)
            return null;

        //  If the reply is fully received, flip the FSM into request-sending state.
        if (!msg_.has_more()) {
            receiving_reply = false;
            message_begins = true;   //这里recv的数据已经接受完了,那么将这个标志位复位
        }

        return msg_;
    }

其实代码还是很简单吧,主要的接收和发送都还是通过Dealer的方法来实现的,这里无非是多了一点空的标志msg的处理而已。。。基本上的内容都在注释里面交代清楚了。。。。

总的来说还是很简单吧,不过Req对Session进行了扩展。。。具体如下:

    public static class ReqSession extends Dealer.DealerSession {
        
        
        enum State {
            identity,
            bottom,
            body
        };

        State state;
        
        public ReqSession(IOThread io_thread_, boolean connect_,
            SocketBase socket_, final Options options_,
            final Address addr_) {
            super(io_thread_, connect_, socket_, options_, addr_);
            
            state = State.identity;   //最开始的状态是标志,因为连接一开始建立,就将会发送identity,之后就在bottom和body里面循环了
        }
        
        @Override
        //该方法用于将数据写到pipe里面,这样上层的socket就可以收到了
        public int push_msg (Msg msg_)
        {
            switch (state) {
            case bottom:
                if (msg_.flags () == Msg.more && msg_.size () == 0) {  //标志msg的特性,肯定是more标志位还有size为0,
                    state = State.body; //接下来就是要接收真正的数据了
                    return super.push_msg (msg_);   //调用sessionBase的方法,这里其实是将数据写到pipe里面去发送给socket
                }
                break;
            case body:
                if (msg_.flags () == Msg.more)
                    return super.push_msg (msg_);
                if (msg_.flags () == 0) {
                    state = State.bottom;   //回归bottom
                    return super.push_msg (msg_);
                }
                break;
            case identity:  //一开始与response连接上之后,就会接收identity
                if (msg_.flags () == 0) {
                    state = State.bottom;  //接下来应该要接收最开始的标志msg
                    return super.push_msg (msg_);
                }
                break;
            }
            
            throw new IllegalStateException(state.toString());
        }
        
        public void reset ()
        {
            super.reset ();
            state = State.identity;
        }

    }

}

这里对于push_msg方法添加了一些状态的扩展。。。可能它的唯一用处就是过滤掉那些无效的msg吧。。。只将有效的正确的msg通过pipe从session交给上层的socket,从而让用户代码接收到。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值