Event-based NiO multi-thread Server

Source: Internet
Author: User
Tags dateformat

Jdk1.4 NiO effectively solves the thread overhead of the original stream I/O. It uses multithreading in NIO, instead of allocating independent service threads to respond to each client request, multi-thread is used to make full use of the processing capability of multiple CPUs and the waiting time during processing to improve the service capability.

The introduction of multithreading makes it easy to further reduce readability and maintainability for the NIO code that is originally a little complicated. Introducing a good design model will not only bring high-performance, high-reliability code, but also bring about a pleasant development process.

Thread Model

NIO selector adopts multiplexing technology. It can process multiple sockets on one selector and perform Io operations by obtaining a read/write channel. Due to network bandwidth and other reasons, it is easy to wait for reading and writing operations in the channel. Therefore, multithreading is introduced in reading and writing operations, which improves performance significantly, in addition, it can improve the quality of service perceived by the client. Therefore, the model in this article will mainly improve the data exchange capability with the client by using the Read and Write thread pools.

As shown in, after the Server accepts the client request, the control thread submits the read channel of the request to the read thread pool, and the read thread pool allocates threads to read the client data; after the read thread completes the read operation, it returns the data to the control thread for service processing on the server. After the service is processed, the data and write channels that need to be responded to the client are submitted to the write thread pool, and the write thread completes the operation of sending response data to the client.

(NIO multi-thread Server Model)

At the same time, the whole server process is established on the event mechanism. In[Accept connections-> Read-> business processing-> write-> Close connection
]In this process, the trigger will trigger the corresponding event, and the event processor will respond to the corresponding event separately to complete service processing on the server side.
Next, let's take a closer look at the components of this model.

Back to Top

Related events are defined in this model. We define some basic events:

(1) onaccept: this event is triggered when the server receives a client connection request. Through this event, we can know that there is a new client incoming call. This event can be used to control the server load. For example, the server can set to only provide services for a certain number of clients at the same time. When the number of requests exceeds the limit, an exception can be thrown in response to this event to reject new connections.

(2) onaccepted: this event is triggered when the client request is accepted by the server. This event indicates that a new client has formally established a connection with the server.

(3) onread: this event is triggered when the client sends data and the data has been correctly read by the control thread of the server. This event notifies the event processor to process the data sent from the client. Note that in this model, the client data is read by the control thread to the read thread, and the event processor does not need to perform special read operations in this event, instead, you only need to directly process the data transmitted from the control thread.

(4) onwrite: this event is triggered when the client can begin to accept the data sent by the server. Through this event, we can send a response to the client. In this model, the event processor only needs to set

(5) onclosed: this event is triggered when the client and server are disconnected.

(6) onerror: this event is triggered when an error occurs between the client and the server from the connection to the last disconnection. Through this event, we can know what errors have occurred.

Back to Top

Implementation of the Event Callback Mechanism

In this model, events are broadcast, that is, all registered event processors can receive Event Notifications. In this way, different types of services can be processed with different processors, so that each processor's business functions can be as single as possible.

For example, the entire event model consists of listeners, event adapters, event triggers, and event processors.

(Event model)

  1. Listener (serverlistener): This is an event interface that defines the server events to be monitored. If you need to define more events, you can expand them here.
     public interface Serverlistener {    public void onError(String error);    public void onAccept() throws Exception;    public void onAccepted(Request request) throws Exception;    public void onRead(Request request) throws Exception;    public void onWrite(Request request, Response response) throws Exception;    public void onClosed(Request request) throws Exception;  }

  2. Event adapter: implements an adapter (eventadapter) for the serverlistener interface. The advantage is that the final event processor can only process the events of interest.

     public abstract class EventAdapter implements Serverlistener {     public EventAdapter() {     }     public void onError(String error) {}     public void onAccept() throws Exception {}     public void onAccepted(Request request)  throws Exception {}     public void onRead(Request request)  throws Exception {}     public void onWrite(Request request, Response response)  throws Exception {}     public void onClosed(Request request)  throws Exception {}  }   

  3. Event trigger (notifier): used to notify the registered event processor to respond to the event when appropriate by triggering a server event. Trigger is implemented in singleton mode to centrally control events on the entire server to avoid confusion.

    Public class notifier {Private Static arraylist listeners = NULL; Private Static notifier instance = NULL; private Notifier () {listeners = new arraylist ();} /*** get event trigger * @ return event trigger */public static synchronized notifier getnotifier () {If (instance = NULL) {instance = new Notifier (); return instance;} else return instance;}/*** add event listener * @ Param l listener */Public void addlistener (SERV Erlistener L) {synchronized (listeners) {If (! Listeners. contains (L) listeners. add (l) ;}} public void fireonaccept () throws exception {for (INT I = listeners. size ()-1; I> = 0; I --) (serverlistener) listeners. get (I )). onaccept ();}.... // other fire method}

  4. Event processor (handler): inherits the event adapter and responds to events of interest to implement business processing. The following is a simple event processor implementation that responds to the onread event and prints data read from the client on the terminal.

     public class ServerHandler extends EventAdapter {     public ServerHandler() {     }     public void onRead(Request request) throws Exception {         System.out.println("Received: " + new String(data));     }  } 

  5. Event processor registration. To enable the event processor to receive event notifications from the service thread, the event processor must register in the trigger.
     ServerHandler handler = new ServerHandler();  Notifier.addlistener(handler); 

Back to Top

Implementing NiO multi-thread Server

NIO multi-thread server consists of the master service thread, read thread, and write thread.

(Thread model)

  1. Master service thread (server): The Master thread creates a read and write thread pool to listen to and accept client requests. Meanwhile, the Read and Write channels are submitted by the corresponding reader thread) and writer. The read and write threads read data from the client and respond to the client respectively.

    Public class server implements runnable {.... private Static int max_threads = 4; public server (INT port) throws exception {.... // create a non-blocking network with selector = selector. open (); sschannel = serversocketchannel. open (); sschannel. configureblocking (false); Address = new inetsocketaddress (port); serversocket Ss = sschannel. socket (); SS. BIND (Address); sschannel. register (selector, selectionkey. op_accept);} public void run () {system. out. println ("server started... "); system. out. println ("server listening on port:" + port); // listen to while (true) {try {int num = 0; num = selector. select (); If (Num> 0) {set selectedkeys = selector. selectedkeys (); iterator it = selectedkeys. iterator (); While (it. hasnext () {selectionkey key = (selectionkey) it. next (); it. remove (); // process Io event if (key. readyops () & selectionkey. op_accept) = selectionkey. op_accept) {// accept the new connection serversocketchannel SSC = (serversocketchannel) Key. channel (); notifier. fireonaccept (); socketchannel SC = SSC. accept (); SC. configureblocking (false); // triggers the request that accepts the connection event request = new request (SC); notifier. fireonaccepted (request); // register the read operation to perform the next read operation SC. register (selector, selectionkey. op_read, request);} else if (key. readyops () & selectionkey. op_read) = selectionkey. op_read) {// submit the read service thread to read the client data reader. processrequest (key); key. cancel ();} else if (key. readyops () & selectionkey. op_write) = selectionkey. op_write) {// submit the write service thread to send a response data writer to the client. processrequest (key); key. cancel () ;}} else {addregister (); // register a new write channel in selector} catch (exception e) {notifier. fireonerror ("error occured in server:" + E. getmessage (); Continue ;}}}....}

  2. Read thread (Reader): uses the thread pool technology to read client data through multiple threads to make full use of network data transmission time and improve reading efficiency.
    Public class reader extends thread {public void run () {While (true) {try {selectionkey key; synchronized (pool) {While (pool. isempty () {pool. wait ();} key = (selectionkey) pool. remove (0) ;}// read client data and trigger the onread event read (key) ;}catch (exception e) {continue ;}}}....}

  3. Writer: similar to read operations, a thread pool is used to send server-side data back to the client.
    Public final class writer extends thread {public void run () {While (true) {try {selectionkey key; synchronized (pool) {While (pool. isempty () {pool. wait ();} key = (selectionkey) pool. remove (0);} // send data to the client, close the connection, and trigger the onwrite and onclosed events respectively write (key);} catch (exception E) {continue ;}}}....}

Back to Top

Specific Application

The implementation of the NIO multi-threaded model has come to an end. Now, we can leave aside all the APIs and cumbersome calling methods of NiO, so that we can focus on our practical application.
Let's use a simple timeserver (Time query server) to see how simple the model can bring about development.
In this timeserver, the Time query service is provided in two languages (Chinese and English. We will read the query command (GB/EN) from the client and respond to the current time in the corresponding language format. The server logs the response to the customer's request. As an example, for logging, we simply output the client access time and IP address to the server terminal.

  1. Timehandler ):
    Public class timehandler extends eventadapter {public timehandler () {} public void onwrite (request, response) throws exception {string command = new string (request. getdatainput (); string time = NULL; Date = new date (); // judge the query command if (command. equals ("GB") {// Chinese format dateformat cndate = dateformat. getdatetimeinstance (dateformat. full, dateformat. full, locale. china); time = cndate. format (date);} else {// english format dateformat endate = dateformat. getdatetimeinstance (dateformat. full, dateformat. full, locale. US); time = endate. format (date);} response. send (time. getbytes ());}}
  2. Loghandler ):
    public class LogHandler extends EventAdapter {     public LogHandler() {     }     public void onClosed(Request request) throws Exception {         String log = new Date().toString() + " from " + request.getAddress().toString();         System.out.println(log);     }     public void onError(String error) {         System.out.println("Error: " + error);     } }

  3. Start the program:
    public class Start {     public static void main(String[] args) {         try {             LogHandler loger = new LogHandler();             TimeHandler timer = new TimeHandler();             Notifier notifier = Notifier.getNotifier();             notifier.addlistener(loger);             notifier.addlistener(timer);             System.out.println("Server starting ...");             Server server = new Server(5100);             Thread tServer = new Thread(server);             tServer.start();         }         catch (Exception e) {             System.out.println("Server error: " + e.getMessage());             System.exit(-1);         }     }  }

Back to Top

Summary

Through the example, we can see that the NIO multi-threaded Server Model Based on Event Callback provides a clear and intuitive implementation method that allows developers to get rid of NiO and multithreading technical details, focus on specific business implementations.

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.