These two days like Hadoop write Java RPC framework, using PB as the serial number tool, when writing data encountered a small pit. Before the NIO code was written, it was the wrong code that produced the correct logic and mistakenly thought that it was written correctly. Now simply tidy up.
There are 4 scenarios to handle when using Nio,select () to read events:
1. The channel also has data to continue reading.
2. There is no data in the channel, but the channel has not been disconnected, this is the number of data read to 0, the end of the read, continue to select () to block the waiting data.
3. The other end Channel.close () closes the connection, when the Read channel returns the number of reads 1, indicating that it has reached the end, the same as when reading the file to the end. Now that it is over, cancel the corresponding Selectionkey, indicating that selector no longer listens for read events on the channel. and close the connection, this side channel.close ().
4. The other end is forced to close, that is, the channel without close () is forced to disconnect, this time the side throws a IOException exception to handle this exception.
Before closing the connection to the other end of the Channel.close () there is no scrutiny, and it is unclear what the read number of the channel returned by 1 means. Then there is no cancel corresponding to the Selectionkey, and the connection is not closed, and the result is that selector.select () always returns the Read event, but no data.
Paste the server and client code directly:
Server:
Packagesocket;Importjava.io.IOException;Importjava.net.InetSocketAddress;ImportJava.net.ServerSocket;ImportJava.nio.ByteBuffer;ImportJava.nio.channels.SelectionKey;ImportJava.nio.channels.Selector;ImportJava.nio.channels.ServerSocketChannel;ImportJava.nio.channels.SocketChannel;ImportJava.util.Iterator;ImportJava.util.Set; Public classNIOServer2 {Private voidStartServer ()throwsIOException {Selector Selector=Selector.open (); {Serversocketchannel SSC=Serversocketchannel.open (); Ssc.configureblocking (false); ServerSocket SS=Ssc.socket (); Inetsocketaddress Address=NewInetsocketaddress (9000); Ss.bind (address); System.out.println ("SSC 0:" +SSC); System.out.println ("SS 0:" +SS); Selectionkey Acceptkey=Ssc.register (selector, selectionkey.op_accept); System.out.println ("Acceptkey:" +Acceptkey); Printkeyinfo (Acceptkey); System.out.println ("Going to listen on 9000"); } while(true) {System.out.println ("===================================\nstart Select ..."); intnum =Selector.select (); System.out.println ("Nioserver:number of keys after select operation:" +num); Set<SelectionKey> Selectionkeys =Selector.selectedkeys (); Iterator<SelectionKey> it =Selectionkeys.iterator (); while(It.hasnext ()) {Selectionkey key=It.next (); System.out.println ("Key:" +key); Printkeyinfo (key); It.remove (); if((Key.readyops () & selectionkey.op_accept) = =selectionkey.op_accept) {System.out.println ("Select ACCEPT"); Serversocketchannel SSC=(Serversocketchannel) Key.channel (); Socketchannel SC=ssc.accept (); Sc.configureblocking (false); System.out.println ("SSC 1:" +SSC); System.out.println ("SC 1:" +SC); Selectionkey NewKey=Sc.register (selector, selectionkey.op_read); System.out.println ("New key:" +NewKey); Printkeyinfo (NewKey); } Else if((Key.readyops () & selectionkey.op_read) = =selectionkey.op_read) {//System.out.println ("select READ");//System.out.print ("before Cancel:");p rintkeyinfo (key);//Key.cancel ();//System.out.println ("after Cancel:");p rintkeyinfo (key);Socketchannel sc =(Socketchannel) Key.channel (); System.out.println ("SC 2:" +SC); //echo Data//The following processing is correct, count<0 cancel key. The count=0 enters the next round of select () blocking wait data. //try {//int count = Doread (key);//if (Count < 0) {//Key.cancel ();//System.out.println ("Cancel key for < 0");//Sc.read (Bytebuffer.allocate (2));// }//} catch (IOException e) {//e.printstacktrace ();//Key.cancel ();//System.out.println ("Cancel Key");// } //The following process is wrong, and the correct logic appears in the occasional case. After the client writes continuously, closes the connection immediately, then the code below can print out the client's output,//The client closes the connection, and the following code immediately bursts out the exception, which is the line of code. Java.io.IOException: The software in your console aborted an established connection. //int nbytes = 0;//Bytebuffer Echobuffer = bytebuffer.allocate (+);//While (true) {//echobuffer.clear ();//int r = sc.read (Echobuffer);//System.out.println (New String (Echobuffer.array ()));//if (r <= 0) break;//Echobuffer.flip ();//Sc.write (echobuffer);//nbytes + = r;// }//System.out.println ("echoed" + Nbytes + "from" + SC); //The following is the correct process. The right way to do this is to handle the read to n,0,-1 separately, and to handle the client-forced shutdown exception . while(true) {Bytebuffer buffer= Bytebuffer.allocate (2); Buffer.clear (); intR; Try{R=sc.read (buffer); System.out.println ("R =" +R); System.out.println (NewString (Buffer.array ())); if(R < 0) { //client Socket.close () will come here and read the number R=-1Key.cancel (); System.out.println ("Cancel key for < 0"); Break; } Else if(r = = 0) { //the client socket is not closed, and the channel has no data and the number of data is r=0. //sometimes select () returns, but the channel does not necessarily have data. Maybe select () is awakened by another method Break; } } Catch(IOException e) {//client forced shutdown will come here to report an exceptionE.printstacktrace (); Key.cancel (); System.out.println ("Cancel key for Exception"); Break; } }// while}//If ... else if//try {//Thread.Sleep (+);//} catch (Interruptedexception e) {//e.printstacktrace ();// }}// while}// while } Private intDoread (Selectionkey key)throwsIOException {Socketchannel channel=(Socketchannel) Key.channel (); while(true) { intCount =-1; Bytebuffer Buffer= Bytebuffer.allocate (2); if(buffer.remaining () > 0) {Count=channel.read (buffer); System.out.println ("Count =" +count); if(Count <= 0)returncount; } } } Private Static voidPrintkeyinfo (Selectionkey SK) {String s=NewString (); S= "Att:" + (sk.attachment () = =NULL? "No": "Yes"); S+ = ", Read:" +sk.isreadable (); S+ = ", Acpt:" +sk.isacceptable (); S+ = ", cnct:" +sk.isconnectable (); S+ = ", Wrt:" +sk.iswritable (); S+ = ", Valid:" +Sk.isvalid (); S+ = ", Interestops:" +Sk.interestops (); S+ = ", Readyops:" +Sk.readyops (); System.out.println (s); } Public Static voidMain (string[] args) {Try { NewNIOServer2 (). StartServer (); } Catch(IOException e) {e.printstacktrace (); } }}
Client:
Packagesocket;ImportJava.io.DataOutputStream;Importjava.io.IOException;ImportJava.net.Socket;Importjava.net.UnknownHostException; Public classsocketclient { Public Static voidMain (string[] args)throwsunknownhostexception, IOException, interruptedexception {socket socket=NewSocket ("localhost", 9000); DataOutputStream out=NewDataOutputStream (Socket.getoutputstream ()); byte[] bytes = "FDFD". GetBytes ();//System.out.println ("Send FDFD");out.write (bytes); Out.flush (); //Thread.Sleep (15*1000); //System.out.println ("Send Loll");Out.write ("Loull". GetBytes ()); Out.flush (); //Thread.Sleep (1*1000);Socket.close (); System.out.println ("Client socket Close"); }}
Wasted some time, on the one hand because I am not familiar with the network programming, such as unclear-1 what meaning. On the other hand, Java NiO's API is still slightly more difficult to use.
Java NIO read Data processing process