Implementation of WCF Extensions ZEROMQ binding and Protocolbuffer message encoding (iii) Implementation Replychannel (2016-03-15 12:35)

Source: Internet
Author: User



This is the third article in this series, other articles please click the following directory



Implementation of WCF Extensions ZEROMQ binding and Protocolbuffer message encoding (i) Overview design



Implementation of the WCF extension ZEROMQ binding and Protocolbuffer message encoding (ii) Implementation IRequestChannel



Implementation of the WCF extension ZEROMQ binding and Protocolbuffer message encoding (c) Implementation Replychannel






It's more complicated than Requestchannel,replychannel.



1 Starting the ZMQ Rep node



First, you need to overload the OnOpen method to start the ZMQ rep node, primarily calling the Createsocket method and the binding address.


 
protected override void OnOpen(TimeSpan timeout)
        { if (this.socket == null)
            { this.socket = this.zmqContext.CreateSocket(SocketType.REP); int trimIPEnd = this.localAddress.Uri.AbsoluteUri.LastIndexOf(‘:‘); string trimIP = this.localAddress.Uri.AbsoluteUri.Substring(trimIPEnd,this.localAddress.Uri.AbsoluteUri.Length - trimIPEnd); string zmqServerAddress = "tcp://*" + trimIP;
                socket.Bind(zmqServerAddress);
            }
        }


2 implement Receivereqeust, return to context



As with Requestchannel, a synchronous version of Receiverequest is implemented. This method is a method of the IReplyChannel interface. Why does the interface method return RequestContext instead of returning a message? The reason is that WCF can send a reply message based on RequestContext after it receives requestcontext.


    public RequestContext ReceiveRequest(TimeSpan timeout)
        {
            ThrowIfDisposedOrNotOpen();

            Message request = this.ReceiveMessage(timeout); return new ZMQRequestContext(this, request, timeout);
        }
The implementation of ReceiveMessage is used in the base class zmqchannelbase in order to reuse.
  public Message ReceiveMessage(TimeSpan timeout)
        { base.ThrowIfDisposedOrNotOpen(); byte[] replyData = bufferManager.TakeBuffer(1000); int replaySize = socket.Receive(replyData);
                
            Message response = encoder.ReadMessage( new ArraySegment<byte>(replyData, 0, replaySize), bufferManager);
            bufferManager.ReturnBuffer(replyData); return response;
        }


3 Synchronous version of the Receiverequest implementation, and then implement the asynchronous version of the



WCF uses Replychannel to receive messages, and Beginreceiverequest is called by default.



The implementation of the asynchronous version is also used. NET amp async mode. The steps to invoke are as follows: performed from top to bottom. The remote request first enters Replychannel's Begintryreceiverequest method, which returns the Tryreceiverequestasyncresult instance. Then execute down in turn until the Socket.receive () method of ZMQ is executed in Basechannel.socketreceiveasyncresult.


Remote request
A kind of
ReplyChannel                                            BeginTryReceiveRequest
A kind of
TryReceiveRequestAsyncResult                                  new
A kind of
BaseChannel                                                BeginReceiveRequest
A kind of
ReceiveRequestAsyncResult                                      new
A kind of
BaseChannel                                                BeginReceiveMessage
A kind of
BaseChannel                                                BeginReadData
A kind of
BaseChannel.SocketReceiveAsyncResult                        new
A kind of
Asynchronous agent executes socket.receive
A kind of
BaseChannel                                                    EndReadData
A kind of
Basechannel endreceivemessage deserialize message to data here 


A lot of steps, every step has meaning, Begintryreceiverequest first receives a request message and handles the timeout so that it does not throw an exception. Transfer to Beginreceiverequest, create a Receiverequestasyncresult object, and call the base class's beginreceivemessage in its construction. The beginreceivemessage of the base class is purely for the reusability of the code. Transfer to Beginreaddata, create Socketreceiveasyncresult object, is really start socket. Receive (), where asynchronous delegates are used in a way that implements Asynchrony.


4 Resolve ZMQ synchronization limits after the necessary interfaces are implemented, you can start the WCF service to receive requests from the ZMQ client. Once the message is received, it is executed again to the socket. Receive (), an exception occurred while trying to receive the message again. The exception display "node cannot perform this operation in its current state." Because it is the first time to use ZMQ, I do not understand the mechanism of ZMQ. Executes the socket for the first time. Receive () Receives the message normally and executes the socket for the second time. Receive () will go wrong. I also checked the demo of ZMQ and executed to the second socket. Receive (), there is no such problem. By comparing the socket state discovery at the same time:
My program
After the socket receives the message,
ReceiveStatus: Received
The return value has not been returned, so: my program
After the socket receives the message,
ReceiveStatus: Received
The return value has not been returned, so:
SendStatus: None
Demo of ZMQ
After the socket receives the message,
ReceiveStatus: Received
Reply return value
SendStatus: Sent
SendStatus: None
Demo of ZMQ
After the socket receives the message,
ReceiveStatus: Received
Reply return value
SendStatus: Sent 


The ZMQ rep socket must receive the request and send it back before it can receive the request again. My program due to the invocation of the WCF service, has been in the debug state, so did not return in time, resulting in sendstatus is none, so can not be sent again.



Solving this problem is also very simple, using ManualResetEvent. After receiving the message, place the ManualResetEvent in the reset state and call ManualResetEvent's WaitOne () before receive (), waiting for the send to return. Once the Replychannel sends the return, the ManualResetEvent is placed in the set state immediately and the receive () is executed.



When receiving


 
 
         serviceHanledDone.WaitOne();
                    int receiveLength = socket.Receive(data1);
                    serviceHanledDone.Reset();
                    return receiveLength;


After sending, the ManualResetEvent is placed into set immediately, allowing the WaitOne to be released.


 Socket. Send (data);                    Servicehanleddone.set ();


5 adding ZMQ queue support



At this point, zmqbinding can receive a request from the ZMQ client and return it correctly. However, it seems that only one request can be received at a time, waiting for a reply before receiving the next request. While WCF processing is asynchronous, ZMQ's rep node limits the processing power of the server, so how can I receive multiple requests? Since ZMQ is called "MQ", it has the function of queue. The ZMQ manual knows that Router-dealer is capable of implementing a queue. The ZMQ version I use is CLRZMQ, but there is no CLRZMQ implementation of Router-dealder example code on the Web. In the CLRZMQ code, I found that the Clrzmq Queuedevice class implements the Router-dealer mode of ZMQ. And it's easy to use. See my other articles for a complete ZMQ example.



Note here that Queuedevice should start first and then start the rep node. Therefore, the ManualResetEvent object is also used. Queuedecvice starts in a new thread and notifies the rep node when it starts. The code is this:


protected override void OnOpen(TimeSpan timeout)
{
if (this.socket == null)
{
startRouterDealer(this.zmqContext);
_deviceReady.WaitOne();
this.socket = this.zmqContext.CreateSocket(SocketType.REP);
int trimIPEnd = this.localAddress.Uri.AbsoluteUri.LastIndexOf(‘:‘);
string trimIP = this.localAddress.Uri.AbsoluteUri.Substring(trimIPEnd,this.localAddress.Uri.AbsoluteUri.Length - trimIPEnd);
string zmqServerAddress = "tcp://*" + trimIP;
//socket.Bind(zmqServerAddress);
socket.Connect("inproc://backend");
}
}
protected override void OnClosing()
{
base.OnClosing();
}
private static void startRouterDealer(ZmqContext context)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(startQueueDeviceThread), context);
}
private static void startQueueDeviceThread(object state)
{
ZmqContext context = state as ZmqContext;
//Thread.Sleep(2000);
using (QueueDevice queue = new QueueDevice(context,
"tcp://*:5555",
"inproc://backend",
DeviceMode.Threaded))
{
queue.Initialize();
_deviceReady.Set();
queue.Start();
While (true)
{
Thread.Sleep(1000);
}
}
} 


So far, the transport part of Zmqbinding has been completed. The next article begins with the Protocolbuffer message encoding and how it is encoded and decoded in WCF.









Implementation of the WCF extension ZEROMQ binding and Protocolbuffer message encoding (c) Implementation Replychannel (2016-03-15 12:35)


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.