Unconsciously, has been so long time has not updated things, said really embarrassed AH. (mainly in the recent technology has become more and more the sense of the less-_-| | | )
I've been learning about Linux lately. Once again, I am exposed to the I/O multiplexing model (Select/poll/epoll), and as a result of not having written code with NIO for a long time, try to write an example today to consolidate the understanding of the I/O multiplexing model. This no, met a pit, also produced a little doubt. ^_^.
Simple description: The selector Select method returns a key collection that has a selectionkey that is readable, but calls the Read method of the channel associated with this selectionkey, always returning a read length of 1. Since 1 is returned, you can indicate that the TCP link has been disconnected. The next call to the Select method should not return this selectionkey, nor should this selectionkey be readable. But that is not the case:
public class Niomain {public static void main (string[] args) throws Exception {Selector Selector = Selector.open (); Serversocketchannel Serverchannel = Serversocketchannel.open (); serverchannel.configureblocking (false); Serverchannel.socket (). bind (New inetsocketaddress (9000), Serverchannel.register (selector, selectionkey.op_ ACCEPT);d Oselect (selector);} public static void Doselect (Selector Selector) throws Exception{while (true) {int srt=selector.select (); if (srt<=0) { Continue;} set<selectionkey> keys = Selector.selectedkeys ();iterator<selectionkey> iter = Keys.iterator (); while ( Iter.hasnext ()) {Selectionkey key = Iter.next (); if (Key.isacceptable ()) {Serversocketchannel schannel= ( Serversocketchannel) Key.channel (); Socketchannel Cchannel = schannel.accept (); cchannel.configureblocking (false); Cchannel.register (selector, Selectionkey.op_read);} else if (key.isreadable ()) {Socketchannel Cchannel = (socketchannel) key.channel (); Bytebuffer BB = bytebuffer.allocate (1024x768); int Len =cchannel. read (BB); Bb.flip (), if (Bb.hasarray () && len>0) {System.out.println ("from client" + ":" + new String (Bb.array (), 0,len)); int newinterestops = Key.interestops (); Newinterestops |= Selectionkey.op_write;key.interestops ( Newinterestops);} else if (len==-1) {System.out.println ("no Data");//cannot forget to close channel}bb.clear ();} Iter.remove ();}}}
Run this code, then enter 127.0.0.1:9000 in the browser, carriage return. The result is the information in the console that first prints out the HTTP protocol. And then the dead loop prints no data. The reason can be imagined, the browser after initiating an HTTP request, a certain time does not get the server side of the corresponding, will disconnect the TCP link. At this point the Read method of the channel returns-1. The pit is that the link has been disconnected, and selector can select it and is always readable. This led to a dead cycle of printing no data. If this happens in the production environment, the consequences are really unimaginable.
Although the solution is relatively simple, it can not be overlooked. When the channel's Read method returns-1 o'clock. Call the channel's Close method to close the channel. The top code is to add a line where no data is printed: Cchannel.close (). So the channel corresponding to the Selectionkey will not be a select out again. There is no longer a cycle of death.
In NIO programming I have always had a doubt or uncertainty about when to call the channel's write method to return the data to the client.
There are only two examples of code seen on the web.
- directly back--- server-side read the data sent by the client, directly call the channel's write method to return the data to the client.
- registers the writable event, after which the writable event occurs and then returns--- the server reads the data from the client, and then registers the channel with the selector to be interested in writable. When writable, the channel.write is then called to write the data. But this approach must be noted: when the data is finished, it is important to cancel the interest of the writable event. Otherwise the server will be busy crashing.
Both of these methods seem to work, and there are no problems with running some examples. But the mind is always feeling a little unclear enough to be cheerful (probably because the underlying implementation of the system is not clear why). Java has some mature open-source nio frameworks, such as Netty, Mina. Why don't you go and see how they handle it? OK, let's see how Mina is implemented. (I'm looking at the mina2.0.2 version)
Next is the code for the Flushnow method I traced to Abstractpollingioprocessor.
Because the space does not stick to the entire code of the WriteBuffer method, its critical invocation: The WriteBuffer method is also returning the Localwrittenbytes returned by the Write method. Let's take a closer look at the implementation of the Write method. And see what the hell is going on back there.
Aside from the rest of the details, let's take a look at how to implement the return data to the customer, Mina directly from the session to get the associated Socketchannel, and then directly call Socketchannel's Write method to write data to the client, and record the length of the write data.
Let's go back to the beginning Flushnow method:
As you can see, when the channel writes out the length of the data is greater than 0, and the buff has data to write. The Setinterestedinwrite method is called, and the method name is also known to be interested in registering the Write event, so let's see the code clearly.
Yes, it is true that you are interested in registering for a write event. There is also a judgment on the localwrittenbytes equal to zero behind the Flushnow method:
Through the comments in the source code, we know that when localwrittenbytes equals zero, that is, the call to the channel's write does not write any data, this is the kernel buufer full, is not writable state. So here also call the Setinterestedinwrite method to register writable interest, to wait for the writable event to occur before sending the data to the client.
To summarize the implementation of Mina is: After reading the data requested by the client, the call channel's write method to return data to the customer, if the channel's write method does not send all the data to be returned, register to be interested in writable, Continue sending until the next writable event is triggered.
Write to this, there is not clear what to say, the inaccurate place, but also look at the master Feel Free (*^__^*) ...
A little memory of NiO's pit