Currently, distributed computing Web services are prevalent, and the underlying layers of these network services are inseparable from socket operations. They all have a common structure:
1. Read Request
2. Decode request
3. Process Service
4. encode reply
5. Send reply
The classic network service is designed to process data in each thread:
However, when the user load increases, the performance will decrease very quickly. We need to find a new solution to ensure smooth data processing. Obviously, the event trigger mechanism is the best solution. when an event occurs, handler is triggered, then start data processing.
The reactor mode is similar to event processing in AWT:
Reactor mode participant
1. The reactor is responsible for responding to Io events. Once an event occurs, the broadcast is sent to the corresponding handler for processing. This is similar to the AWT thread
2. handler is responsible for non-blocking behaviors, similar to AWT actionlisteners. It is also responsible for binding handlers to Event Events, similar to AWT addactionlistener.
Java NiO provides a basic implementation mechanism for the reactor mode. When its selector finds that a channel has data, it will notify us through slectorkey. Here we implement event binding and handler binding.
Let's take a look at the reactor mode.Code:
Public class reactor implements runnable { Final selector; Final serversocketchannel serversocket; Reactor (INT port) throws ioexception { Selector = selector. open (); Serversocket = serversocketchannel. open (); Inetsocketaddress address = new inetsocketaddress (inetaddress. getlocalhost (), Port ); Serversocket. socket (). BIND (Address ); Serversocket. configureblocking (false ); // Register the channel with Selector Selectionkey Sk = serversocket. Register (selector, selectionkey. op_accept ); Logger. debug ("--> Start serversocket. register! "); // Use the attache function of SK to bind an acceptor. If something happens, the acceptor is triggered. SK. Attach (New Acceptor ()); Logger. debug ("--> attach (New Acceptor ()! "); } Public void run () {// normally in a new thread Try { While (! Thread. interrupted ()) { Selector. Select (); Set selected = selector. selectedkeys (); Iterator it = selected. iterator (); // If selector finds that the channel has an op_accept or read event, the following traversal will be performed. While (it. hasnext ()) // First trigger an accepter thread for an event // Trigger socketreadhandler later Dispatch (selectionkey) (it. Next ())); Selected. Clear (); } } Catch (ioexception ex ){ Logger. debug ("reactor stop! "+ Ex ); } } // Run acceptor or socketreadhandler Void dispatch (selectionkey K ){ Runnable r = (runnable) (K. Attachment ()); If (R! = NULL ){ // R. Run (); } } Class acceptor implements runnable {// inner Public void run (){ Try { Logger. debug ("--> ready for accept! "); Socketchannel c = serversocket. Accept (); If (C! = NULL) // Call handler to process the channel New socketreadhandler (selector, C ); } Catch (ioexception ex ){ Logger. debug ("Accept stop! "+ Ex ); } } } } |
The above code cleverly uses the attetchannel attach function to link hanlder with the channel that may have events. when an event occurs, handler of the corresponding link can be triggered immediately.
Let's look at the handler code:
Public class socketreadhandler implements runnable { Public static logger = logger. getlogger (socketreadhandler. Class ); Private test = new test (); Final socketchannel socket; Final selectionkey SK; Static final int reading = 0, sending = 1; Int state = reading; Public socketreadhandler (selector Sel, socketchannel C) Throws ioexception { Socket = C; Socket. configureblocking (false ); SK = socket. Register (SEL, 0 ); // When the selectionkey is bound to this handler and an event is triggered next, the run method of this class is called. // See dispatch (selectionkey K) SK. Attach (this ); // Mark selectionkey as readable for reading at the same time. SK. interestops (selectionkey. op_read ); Sel. Wakeup (); } Public void run (){ Try { // Test. Read (socket, input ); Readrequest (); } Catch (exception ex ){ Logger. debug ("readrequest error" + ex ); } } /** * Processing and reading data * @ Param key * @ Throws exception */ Private void readrequest () throws exception { Bytebuffer input = bytebuffer. Allocate (1024 ); Input. Clear (); Try { Int bytesread = socket. Read (input ); ...... // Activate the thread pool to process these requests Requesthandle (new request (socket, BTT )); ..... } Catch (exception e ){ } } |
Note that the handler executes attach again. In this way, overwrite the previous acceptor. The next time the Handler has a read event, the handler will be directly triggered. the data read, write, and other processes are started.
After reading data, you can make these data processing threads into a thread pool. In this way, the data is read and immediately thrown into the thread pool to accelerate the processing speed:
Furthermore, we can use multiple selectors to process connection and read events respectively.
A high-performance Java Network Service mechanism is coming into being, and exciting cluster parallel computing is coming soon.