In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
Editor to share with you how to use JavaNIOSelector, I believe that most people do not know much about it, so share this article for your reference, I hope you can learn a lot after reading this article, let's go to know it!
The details are as follows:
1. The core components of Java NIO
The core components of Java NIO include: Channel (channel), Buffer (buffer), Selector (selector), of which Channel and Buffer are easier to understand.
To put it simply, NIO is channel-and buffer-oriented, meaning that data is always read from the channel into the buffer buffer, or written from the buffer to the channel.
For a detailed explanation of Channel and Buffer, see the Java NIO tutorial
II. Java NIO Selector
1. Brief introduction to Selector
Selectors provide the ability to select and execute tasks that are already in place. From an underlying point of view, Selector provides the ability to ask if the channel is ready to perform each Icano operation. Selector allows multiple Channel to be processed in a single thread. The advantage of using only a single thread to handle multiple Channels is that fewer threads are required to process the channel. In fact, you can use only one thread to process all channels, which greatly reduces the overhead of context switching between threads.
Before you begin, you need to review Selector, SelectableChannel, and SelectionKey:
Selector (Selector)
The Selector selector class manages the information about a set of registered channels and their ready state. The channel is registered with the selector, and the selector is used to update the channel's ready state. When doing so, you can choose to suspend the fired thread until a channel is ready.
Selectable channel (SelectableChannel)
The abstract class SelectableChannel provides the public methods needed to implement the selectivity of the channel. It is the parent of all channel classes that support readiness checking. Because the FileChannel class does not inherit SelectableChannel, it is not an optional channel, and all socket channels are optional, including those obtained from the Pipe object. The SelectableChannel can be registered with the Selector object, and you can specify which operation is of interest to that selector. A channel can be registered with multiple selectors, but only once for each selector.
Select key (SelectionKey)
The selection key encapsulates the registration relationship between a specific channel and a specific selector. The select key object is returned by SelectableChannel.register () and provides a token that represents this registration relationship. The selection key contains two sets of bits (encoded as integers), indicating the channel operations that the registration relationship is concerned about and the operations that the channel is ready for.
The following is a structure diagram for managing multiple channel using Selector:
2. The use of Selector
(1) create a Selector
The Selector object is instantiated by calling the static factory method open (), as follows:
Selector Selector=Selector.open ()
The class method open () actually makes a request to SPI1 to get a new instance through the default SelectorProvider object.
(2) register Channel with Selector
To implement the Selector management Channel, you need to register the channel with the appropriate Selector, as follows:
Channel.configureBlocking (false); SelectionKey key= channel.register (selector,SelectionKey,OP_READ)
It is registered with a selector by calling the channel's register () method. When used with Selector, Channel must be in non-blocking mode, otherwise an IllegalBlockingModeException exception will be thrown, which means that FileChannel cannot be used with Selector because FileChannel cannot switch to non-blocking mode, and socket channels can. In addition, once the channel is registered, it cannot return to the blocking state. If the configureBlocking (true) of the channel is called, a BlockingModeException exception will be thrown.
The second parameter of the register () method is the "interest set", which represents the channel operation that the selector cares about, which is actually a bit mask that represents the operation that the selector needs to care about when checking the channel ready state. For example, if a selector is interested in the read and write operations of a channel, the selector will only check whether the channel's read and write operations are ready when it checks the channel.
It has the following four types of operations:
Connect connection Accept accepts Read read Write write
It is important to note that not all operations are supported on all optional channels, such as ServerSocketChannel supports Accept, while SocketChannel does not. We can use the validOps () method on the channel to get the set of all supported operations under a particular channel.
Four constants are defined in Java to represent these four types of operations:
SelectionKey.OP_CONNECTSelectionKey.OP_ACCEPTSelectionKey.OP_READSelectionKey.OP_WRITE
If Selector is interested in the multi-operation type of the channel, you can use the "bit OR" operator to do this:
Int interestSet=SelectionKey.OP_READ | SelectionKey.OP_WRITE
When a channel triggers an operation, it indicates that an operation of the channel is ready and can be operated. Therefore, a SocketChannel that successfully connects to another server is called "connection ready" (OP_CONNECT). A ServerSocketChannel ready to receive a new incoming connection is called "receive ready" (OP_ACCEPT). A channel with readable data can be said to be "OP_READ". The channel waiting to write data can be said to be "OP_WRITE".
We notice that the register () method returns a SelectionKey object, which we call a key object. This object contains the following four properties:
Interest Collection read Collection Channel Selector
The interest collection is a collection that Selector is interested in, indicating that the selector is concerned about the channel, which can be obtained through the interestOps () of the SelectionKey object. Initially, the interest set is the value passed in when the channel is registered with Selector. The collection is not changed by the selector, but can be changed by interestOps (). We can determine whether Selector is interested in an event in Channel in the following ways:
Int interestSet=selectionKey.interestOps (); boolean isInterestedInAccept = (interestSet & SelectionKey.OP_ACCEPT) = = SelectionKey.OP_ACCEPT
The read collection is a collection of operations that are ready for a channel, indicating that a channel is ready to perform an operation that can be obtained through the readyOps () of the SelctionKey object. It is a subset of the interest collection and represents the operations in the interest collection that have been in place since the last call to select (). (for example, the selector is interested in the read,write operation of the channel, and at some point the read operation of the channel is ready to be learned by the selector, the former is the interest collection, and the latter is the read collection. ). The following methods are defined in JAVA to check whether these operations are ready:
/ / int readSet=selectionKey.readOps (); selectionKey.isAcceptable (); / / equivalent to selectionKey.readyOps () & SelectionKey.OP_ACCEPTselectionKey.isConnectable (); selectionKey.isReadable (); selectionKey.isWritable ()
It is important to note that the ready state indication returned through the readyOps () method of the relevant select key is just a hint, the underlying channel is constantly changing at any time, and other threads may also perform operations on the channel and affect its ready state. In addition, we cannot modify the read collection directly.
Take out the Selector and Channel associated with SelectionKey
Access the corresponding Selector and Channel through SelectionKey:
Channel channel = selectionKey.channel (); Selector selector=selectionKey.selector ()
About canceling the SelectionKey object.
We can cancel a specific registration relationship through the cancel () method of the SelectionKey object. After the method is called, the SelectionKey object is "copied" to the collection of canceled keys, which is now invalid, but the registration relationship is not immediately terminated. The next time you select (), the elements in the unkeyed collection will be cleared and the corresponding registration relationship will really end.
(3) attach objects for SelectionKey binding
One or more additional objects can be bound to the SelectionKey to easily identify a given channel. There are usually two ways:
1 bind directly when registering:
SelectionKey key=channel.register (selector,SelectionKey.OP_READ,theObject)
2 attach after the binding is completed:
SelectionKey.attach (theObject); / / bind
After binding, you can retrieve the object through the corresponding SelectionKey:
SelectionKey.attachment ()
If you want to cancel the object, you can do it this way:
SelectionKey.attach (null)
It is important to note that if the attached object is no longer in use, it must be artificially cleared, because the garbage collector will not recycle the object and will cause a memory leak if it is not cleared.
A single channel can be registered with multiple selectors, and sometimes we need to use the isRegistered () method to check whether a channel has been registered with any of the selectors. Normally, we don't do that.
(4) Select a channel through Selector
We know that selectors maintain a collection of registered channels, and this registration relationship is encapsulated in SelectionKey. Let's take a brief look at the three types of SelectionKey collections maintained by Selector:
Collection of registered keys (Registered key set)
The set of keys generated by all channels associated with the selector is called the set of registered keys. Not all registered keys are still valid. This collection is returned by the keys () method and may be empty. This collection of registered keys is not directly modifiable; an attempt to do so will raise a java.lang.UnsupportedOperationException.
Collection of selected keys (Selected key set)
A subset of the collection of registered keys. Each member of this collection is an operation that the associated channel is determined by the selector (in the previous selection operation) to be ready and contained in the key's interest collection. This collection is returned (and possibly empty) by the selectedKeys () method. Do not confuse the selected key collection with the ready collection. This is a collection of keys, and each key is associated with a channel that is ready for at least one operation. Each key has an embedded ready collection that indicates the operation that the associated channel is ready for. Keys can be removed directly from this collection, but cannot be added. Attempting to add an element to the collection of selected keys throws a java.lang.UnsupportedOperationException.
Collection of cancelled keys (Cancelled key set)
A subset of a collection of registered keys that contains the keys that were called by the cancel () method (this key has been invalidated), but they have not been logged out. This collection is a private member of the selector object and cannot be accessed directly.
In the newly initialized Selector object, all three collections are empty. The select () method of Selector allows you to select channels that are ready (these channels contain events of interest to you). For example, if you are interested in read-ready channels, the select () method returns those channels where the read event is ready. Here are several overloaded select () methods of Selector:
Select (): block until at least one channel is ready for the event you registered. Select (long timeout): same as select (), but the longest blocking event is timeout milliseconds. SelectNow (): non-blocking and returns as soon as the channel is ready.
The int value returned by the select () method indicates how many channels are ready and how many channels have become ready since the last call to the select () method. Channels that previously entered ready in the select () call will not be counted in this call, and channels that were ready in the previous select () call but are no longer ready will not be counted either. For example, when the select () method is called for the first time, 1 is returned if one channel becomes ready, and if the select () method is called again, if another channel is ready, it returns 1 again. If nothing is done on the first ready channel, there are now two channels ready, but only one channel is ready between each call to the select () method.
Once the select () method is called and the return value is not 0, you can access the selected key collection by calling the selectedKeys () method of Selector. As follows:
Set selectedKeys=selector.selectedKeys ()
In turn, it can be put into the Selector and Channel associated with a SelectionKey. As follows:
Set selectedKeys = selector.selectedKeys (); Iterator keyIterator = selectedKeys.iterator (); while (keyIterator.hasNext ()) {SelectionKey key = keyIterator.next (); if (key.isAcceptable ()) {/ / a connection was accepted by a ServerSocketChannel. } else if (key.isConnectable ()) {/ / a connection was established with a remote server. } else if (key.isReadable ()) {/ / a channel is ready for reading} else if (key.isWritable ()) {/ / a channel is ready for writing} keyIterator.remove ();}
About the process of Selector performing the selection
We know that the select () method is called for the channel, and now let's dig into the selection process, that is, the select () execution process. When select () is called, the following steps are performed:
First check the collection of canceled keys, that is, the keys cancelled by cancle (). If the collection is not empty, the keys in the collection are cleared, and each cancelled key in the collection is removed from the registered key collection and the selected key collection. When a key is canceled, it is not immediately removed from the collection, but is "copied" to the cancelled key collection. This cancellation strategy is often referred to as "deferred cancellation". Check the registered key collection again (the interest collection of each key in that collection, to be exact) The bottom layer of the system will ask each registered channel in turn whether it is ready for some operation that the selector is interested in. Once it is found that a channel is ready, it will first determine whether the channel already exists in the selected key set. If so, update the ready set of the corresponding key of the channel in the registered key set. If not, first empty the ready set of the corresponding key of the channel. Then reset the ready collection, and finally save the key to the registered key collection. It is important to understand that when updating the ready collection, the operations already in place in the last select () will not be deleted, that is, the elements in the ready collection are cumulative. For example, the first selector is interested in the read and write operations of a channel, and the read operation of the channel is ready when select () is executed for the first time. At this time, the ready set in the corresponding key of the channel contains the read element, and the second time select () is executed. The write operation for the channel is also ready, and there will be both read and write elements in the ready collection corresponding to the channel.
Go deep into the management of registered key sets
Now that we know how the keys of a channel are added to the selected key set, let's move on to the management of the selected key set. First of all, keep in mind that the selector does not actively delete keys added to the selected key collection, and the ready collection of keys added to the selected key collection can only be set, not cleaned. What if we want to empty the ready collection of a key in the selected key collection? We know that a key will empty the ready collection of that key before adding a new selected key collection, so that we can artificially remove a key from the registered key collection and eventually empty the ready collection of a key. If the removed key is ready again in the next select (), it will be re-added to the collection of selected keys. This is why keyIterator.remove () is called at the end of each iteration.
(5) stop selecting
The selector performs the selection process, and the bottom layer of the system asks whether each channel is ready in turn, which may cause the calling thread to enter a blocking state, so there are three ways to wake up threads blocked in the select () method.
The blocking select () method returns immediately by calling the wakeup () method of the Selector object so that the first selection operation on the selector that has not yet been returned returns immediately. If there is no selection operation in progress, the next call to the select () method will return immediately. Closing Selector** with the close () method wakes up any thread blocked during the selection operation (similar to wakeup ()), while all Channel registered to the Selector are logged out, all keys are canceled, but the Channel itself is not closed. Calling interrupt () calls this method to cause the sleeping thread to throw an InterruptException exception, catch the exception and call wakeup ()
When some people see that "the bottom of the system will ask each channel in turn", they may wonder if it will take a long time if so many keys have been selected. The answer is yes. But what I want to say is that usually you can choose to ignore the process, as to why, we'll talk about it later.
3. NIO multi-person chat room
Server side
Public class ChatServer implements Runnable {private Selector selector; private SelectionKey serverKey; private Vector usernames; private static final int PORT = 9999; SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); public ChatServer () {usernames = new Vector (); init ();} public void init () {try {selector = Selector.open (); / / create serverSocketChannel ServerSocketChannel serverChannel = ServerSocketChannel.open (); ServerSocket socket = serverChannel.socket (); socket.bind (new InetSocketAddress (PORT)); / / add serverChannel.configureBlocking (false) to selector ServerKey = serverChannel.register (selector, SelectionKey.OP_ACCEPT); printInfo ("server starting.");} catch (IOException e) {e.printStackTrace ();}} @ Override public void run () {try {while (true) {/ / get ready channel int count = selector.select (); if (count > 0) {Iterator iterator = selector.selectedKeys (). Iterator (); while (iterator.hasNext ()) {SelectionKey key = iterator.next () / / if the channel of this key is waiting to accept a new socket connection if (key.isAcceptable ()) {System.out.println (key.toString () + ": receive"); / / be sure to remove the server key in this accpet state, otherwise there will be an error iterator.remove (); ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel (); / / accept socket SocketChannel socket = serverChannel.accept (); socket.configureBlocking (false) / / add channel to selector and initially read data socket.register (selector, SelectionKey.OP_READ);} / / if the channel of this key has data readable status if (key.isValid () & & key.isReadable ()) {System.out.println (key.toString () + ": read"); readMsg (key) } / / if the channel of this key is write data status if (key.isValid () & & key.isWritable ()) {System.out.println (key.toString () + ": write"); writeMsg (key);} catch (IOException e) {e.printStackTrace ();}} private void readMsg (SelectionKey key) {SocketChannel channel = null; try {channel = (SocketChannel) key.channel (); / / set buffer buffer ByteBuffer buffer = ByteBuffer.allocate (1024) / / if the client closes the channel, IOException will occur for the read data of the channel. After the Exception is captured, close the channel and cancel the key int count = channel.read (buffer); StringBuffer buf = new StringBuffer (); / / if you read the data if (count > 0) {/ / Let buffer flip, read the data in the buffer buffer.flip (); buf.append (new String (buffer.array (), 0, count)) } String msg = buf.toString (); / / if this data is the data sent when the client connects, if (msg.indexOf ("open_")! =-1) {String name = msg.substring (5); / / take out the name printInfo (name + "--> online"); usernames.add (name); Iterator iter = selector.selectedKeys (). Iterator (); while (iter.hasNext ()) {SelectionKey skey = iter.next () / / if it is not the key of the server socket channel, set the data to this key / / and update the action of interest to this key if (skey! = serverKey) {skey.attach (usernames); skey.interestOps (skey.interestOps () | SelectionKey.OP_WRITE);}} / / if it is the data sent when offline} else if (msg.indexOf ("exit_")! =-1) {String username = msg.substring (5); usernames.remove (username) Key.attach ("close"); / / the current channel to be exited is marked with close, and the interest is changed to write. If close is received in write, break the channel link key.interestOps (SelectionKey.OP_WRITE); Iterator iter = selector.selectedKeys (). Iterator (); while (iter.hasNext ()) {SelectionKey sKey = iter.next (); sKey.attach (usernames); sKey.interestOps (sKey.interestOps () | SelectionKey.OP_WRITE) } / / if chat sends data} else {String uname = msg.substring (0, msg.indexOf ("^")); msg = msg.substring (msg.indexOf ("^") + 1); printInfo ("(" + uname+ ") says:" + msg); String dateTime = sdf.format (new Date ()); String smsg = uname+ "+ dateTime +"\ n "+ msg +"\ n "; Iterator iter = selector.selectedKeys (). Iterator () While (iter.hasNext ()) {SelectionKey sKey = iter.next (); sKey.attach (smsg); sKey.interestOps (sKey.interestOps () | SelectionKey.OP_WRITE);}} buffer.clear () } catch (IOException e) {/ / when the client closes channel, the server will report IOException if it writes or reads data to the channel buffer. The solution is to catch this exception here on the server side and close the Channel channel key.cancel (); try {channel.socket (). Close (); channel.close ();} catch (IOException E1) {e1.printStackTrace () } private void writeMsg (SelectionKey key) {try {SocketChannel channel = (SocketChannel) key.channel (); Object attachment = key.attachment (); / / after obtaining the value of key, leave the value of key empty to avoid affecting the next use of key.attach ("); channel.write (ByteBuffer.wrap (attachment.toString (). GetBytes ()); key.interestOps (SelectionKey.OP_READ);} catch (Exception e) {e.printStackTrace () } private void printInfo (String str) {System.out.println ("[" + sdf.format (new Date ()) + "]->" + str);} public static void main (String [] args) {ChatServer server = new ChatServer (); new Thread (server). Start ();}}
Note that in readMsg and writeMsg, the key of the read operation resets the interest to traverse all the key, while the key of the write operation only needs to set the current key passed in for the reason:
The reason why the read operation traverses the key is that the process of the read and write operation of the channel is:
1. After read to the data, add the data to the attach of each key. When writing data, take the data from the attach of key and write the data to buffer
For example: when there are 3 channel in the selected selector, realize multi-person chat, flow:
1. One of the channel sends data, and the channel receives data 2. 5. In the read operation of the channel, you traverse all the channel, adding the data 3. 5 to the attach of each channel. When each channel writes, it takes the data from the attach of the key and writes the data to its own buffer. So every channel interface can see the data sent by one of the channel.
Client:
Public class ChatClient {private static final String HOST = "127.0.0.1"; private static int PORT = 9999; private static SocketChannel socket; private static ChatClient client; private static byte [] lock = new byte [1]; / / singleton mode management private ChatClient () throws IOException {socket = SocketChannel.open (); socket.connect (new InetSocketAddress (HOST, PORT)); socket.configureBlocking (false);} public static ChatClient getIntance () {synchronized (lock) {if (client = null) {try {client = new ChatClient () } catch (IOException e) {e.printStackTrace ();}} return client;}} public void sendMsg (String msg) {try {socket.write (ByteBuffer.wrap (msg.getBytes ());} catch (IOException e) {e.printStackTrace ();}} public String receiveMsg () {String msg = null; try {ByteBuffer buffer = ByteBuffer.allocate (1024); StringBuffer buf = new StringBuffer (); int count = 0 / / you may not be able to read it all at once. Read while ((count = socket.read (buffer)) > 0) {buf.append (new String (buffer.array (), 0, count));} / / have data if (buf.length () > 0) {msg = buf.toString () If (buf.toString () .equals ("close")) {/ / but sleep will lead to the occurrence of ioException, because if the channel is directly closed here, in server, a read exception will occur when the channel is in read (buffer). Through sleep for a period of time, the channel on the server side shuts down first, and the channel of the client / / closes later. This prevents ioException / / of read (buffer), but this is a stupid method / / Thread.sleep (100) / / better, after catching an exception in readBuffer, manually close the channel socket.socket (). Close (); socket.close (); msg = null;} catch (IOException e) {e.printStackTrace ();} return msg;}}
Interface code: setting name
Public class SetNameFrame extends JFrame {private static final long serialVersionUID = 1L; private static JTextField txtName; private static JButton btnOK; private static JLabel label; public SetNameFrame () {this.setLayout (null); Toolkit kit = Toolkit.getDefaultToolkit (); int w = kit.getScreenSize (). Width; int h = kit.getScreenSize (). Height; this.setBounds (w / 2-2302 / 2, h / 2-200 / 2230200); this.setTitle ("setting name"); this.setDefaultCloseOperation (EXIT_ON_CLOSE); this.setResizable (false) TxtName = new JTextField (4); this.add (txtName); txtName.setBounds (10,10,100,25); btnOK = new JButton ("OK"); this.add (btnOK); btnOK.setBounds (120,10,80,25); label = new JLabel ("[w:" + w + ", h:" + h + "]"); this.add (label); label.setBounds (10,40,200,100) Label.setText ("enter name display width in the text box above:" + w + "display height:" + h + "); btnOK.addActionListener (new ActionListener () {@ Override public void actionPerformed (ActionEvent e) {String uname = txtName.getText (); ChatClient service = ChatClient.getIntance (); ChatFrame chatFrame = new ChatFrame (service, uname); chatFrame.show (); setVisible (false);}}); public static void main (String [] args) {SetNameFrame setNameFrame = new SetNameFrame () SetNameFrame.setVisible (true);}}
Interface code: chat interface
Public class ChatFrame {private JTextArea readContext = new JTextArea (18,30); / / Show message text box private JTextArea writeContext = new JTextArea (6,30); / / send message text box private DefaultListModel modle = new DefaultListModel (); / / user list model private JList list = new JList (modle); / / user list private JButton btnSend = new JButton ("send"); / / send message button private JButton btnClose = new JButton ("close") / / close chat window button private JFrame frame = new JFrame ("ChatFrame"); / / form interface private String uname;// user name private ChatClient service;// is used to interact with the server private boolean isRun = whether false;// is running public ChatFrame (ChatClient service, String uname) {this.isRun = true; this.uname = uname; this.service = service;} / / initialize interface controls and events private void init () {frame.setLayout (null) Frame.setTitle (uname + chat window); frame.setSize (500,500); frame.setLocation (400,200); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setResizable (false); JScrollPane readScroll = new JScrollPane (readContext); readScroll.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); frame.add (readScroll); JScrollPane writeScroll = new JScrollPane (writeContext); writeScroll.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); frame.add (writeScroll); frame.add (list); frame.add (btnSend) Frame.add (btnClose); readScroll.setBounds (10,10,320,300); readContext.setBounds (0,0,320,300); readContext.setEditable (false); readContext.setLineWrap (true); / / Auto wrap writeScroll.setBounds (10,315,320,100); writeContext.setBounds (0,0320,100); writeContext.setLineWrap (true); / / Auto wrap list.setBounds (340,10,140,445); btnSend.setBounds (150,420,80,30) BtnClose.setBounds (250,420,80,30); frame.addWindowListener (new WindowAdapter () {@ Override public void windowClosing (WindowEvent e) {isRun = false; service.sendMsg ("exit_" + uname); System.exit (0);}}); btnSend.addActionListener (new ActionListener () {@ Override public void actionPerformed (ActionEvent e) {String msg = writeContext.getText (). Trim (); if (msg.length () > 0) {service.sendMsg (uname + "^" + writeContext.getText () } writeContext.setText (null); writeContext.requestFocus ();}}); btnClose.addActionListener (new ActionListener () {@ Override public void actionPerformed (ActionEvent e) {isRun = false; service.sendMsg ("exit_" + uname); System.exit (0);}}); list.addListSelectionListener (new ListSelectionListener () {@ Override public void valueChanged (ListSelectionEvent e) {/ / JOptionPane.showMessageDialog (null, / / list.getSelectedValue (). ToString ());}}) WriteContext.addKeyListener (new KeyListener () {@ Override public void keyTyped (KeyEvent e) {/ / TODO Auto-generated method stub} @ Override public void keyReleased (KeyEvent e) {if (e.getKeyCode () = = KeyEvent.VK_ENTER) {String msg = writeContext.getText () .trim (); if (msg.length () > 0) {service.sendMsg (uname + "^" + writeContext.getText ());} writeContext.setText (null); writeContext.requestFocus () } @ Override public void keyPressed (KeyEvent e) {/ / TODO Auto-generated method stub}});} / / this thread class is used to poll messages sent by the reading server private class MsgThread extends Thread {@ Override public void run () {while (isRun) {String msg = service.receiveMsg () If (msg! = null) {/ / if [] exists, this is the if generated by toString of usernames installed on verctor (msg.indexOf ("[")! =-1 & & msg.lastIndexOf ("]")! =-1) {msg = msg.substring (1, msg.length ()-1); String [] userNames = msg.split (","); modle.removeAllElements (); for (int I = 0; I)
< userNames.length; i++) { modle.addElement(userNames[i].trim()); } } else {//如果是普通的消息 String str = readContext.getText() + msg; readContext.setText(str); readContext.selectAll(); } } } } } // 显示界面 public void show() { this.init(); service.sendMsg("open_" + uname); MsgThread msgThread = new MsgThread(); msgThread.start(); this.frame.setVisible(true); }} 分析整个程序的流程: 只有一个客户端连接的注释: [2017-01-23 21:26:14] ->Server starting... .sun.nio.ch.SelectionKeyImpl @ 99436c6: receive sun.nio.ch.SelectionKeyImpl@3ee5015: read [2017-01-23 21:26:19]-> a-> onlinesun.nio.ch.SelectionKeyImpl@3ee5015: write
You can see that the process is as follows: the server accepts channel-> channel for read operation-> channel for write operation
1. When the client's channel calls connect, the server receives the Channel and changes the interest of the channel to read ready 2. 5. After the client connect, the data "open_" is written to the channel buffer immediately, so the channel enters the readable state (that is, the read state), and the interest of the channel is read, so the return value of select () is 1, which enters readMsg (). 3. In readMsg, the status of each key is changed to write state, while the client is always in the read data, asking your server to give me the data, so the channel of the server is in the write state at this time, and the interest of the channel is write, so the return value of select () is 1, entering writeMsg ().
Comments with two client connections:
Sun.nio.ch.SelectionKeyImpl@99436c6: receive sun.nio.ch.SelectionKeyImpl@3ee5015: read [2017-01-23 21:26:19]-> a-> onlinesun.nio.ch.SelectionKeyImpl@3ee5015: write sun.nio.ch.SelectionKeyImpl@99436c6: receive sun.nio.ch.SelectionKeyImpl@3ee5015: write sun.nio.ch.SelectionKeyImpl@12cb94b7: read [2017-01-23 21:32:30]-> b-> onlinesun.nio.ch.SelectionKeyImpl@3ee5015: Write sun.nio.ch.SelectionKeyImpl@12cb94b7: write sun.nio.ch.SelectionKeyImpl@3ee5015: write
As you can see, @ 99436c6 is the ServerSocketChannel,@3ee5015, the first link is the Channel,@12cb94b7, the second connection is the Channel, and you can see that after the second Channel connection
Sun.nio.ch.SelectionKeyImpl@3ee5015: write sun.nio.ch.SelectionKeyImpl@12cb94b7: read [2017-01-23 21:32:30]-> b-> onlinesun.nio.ch.SelectionKeyImpl@3ee5015: write sun.nio.ch.SelectionKeyImpl@12cb94b7: write sun.nio.ch.SelectionKeyImpl@3ee5015: write
The two Channel run alternately, indicating that Selector handles Channle and polling.
The above is all the contents of this article "how to use JavaNIOSelector". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.