1. NIO completes network programming
1.1 Selector boss
Selector Selector, network programming using NIO's big brother!!! The server can execute a thread, run the Selector program, and listen. New connection, connected, read data, write data Common methods of Selector: public static Selector Open(); Get a selector object public int select(long timeout); Listen to all registered channels and store the corresponding information SelectionKey into the internal set if there is IO flow Closing, parameter is a timeout public Set<SelectionKey> selectionKeys(); Returns all selectionkeys saved in the current Selector internal collection
1.2 SelectionKey
SelectionKey Indicates the direct relationship between Selector and network channel Int OP? Accept; 16 connection required Int OP? Connect; 8 connected Int OP? Read; 1 read operation Int OP write; 4 write operation SelectionKey public abstract Selector selector(); Get the Selector object associated with it public abstract SelectableChannel channel(); Get the channel associated with it public final Object attachment(); Get the shared data associated with it public abstract SelectionKey interestOps(int ops); Set or change listening events public final boolean isAcceptable(); Can I accept public final boolean isReadable(); Whether it can be read public final boolean isWritable(); Can I write ##### 1.3 ServerSocketChannel
ServerSocketChannel
Channel channel corresponding to the Socket program of the server
Common methods:
public static ServerSocketChannel open();
Opening the ServerSocketChannel channel channel is equal to starting the server program
public final ServerSocketChannel bind(SocketAddress local);
Set server-side slogans
public final SelectableChannel configureBlocking(boolean block);
Set the blocking or non blocking mode. The value of false indicates that the non blocking mode is adopted
public SocketChannel accept();
[non blocking]
Get a client connection and get the corresponding operation channel
public final SelectionKey register(Selector sel, int ops);
[key methods]
Register the current selector and choose what events to listen to
1.4 SocketChannel
SocketChannel Channel object corresponding to client Socket Common methods: public static SocketChannel open(); Clock in a Socket client Channel object public final SelectableChannel configureBlocking(boolean block) Here you can set whether it is blocking or non blocking false for non blocking public boolean connect(SocketAddress remote); Connect to server public boolean finishConnect(); If the connect connection fails, you can continue to connect through finishConnect public int write(ByteBuffer buf); Write data to buffer stream public int read(ByteBuffer buf); , Read data from buffer stream public final SelectionKey register(Selector sel, int ops, Object attechment); Register the current SocketChannel, select the corresponding listening operation, and it can have the Object attachment parameter public final void close(); Close SocketChannel
1.5 using NIO to complete a client and server
1.5.1 first complete the client
package com.qfedu.a_tcpnio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.Scanner; import java.util.concurrent.ThreadPoolExecutor; /** * Comply with TCP protocol, non blocking IO NIO completes corresponding client code * * @author Anonymous 2020/3/16 15:10 */ public class TcpNioClient { public static void main(String[] args) throws IOException, InterruptedException { // 1. Get a network channel SocketChannel socket = SocketChannel.open(); // 2. Set the current NIO mode as non blocking mode socket.configureBlocking(false); // 3. Determine the server IP address and corresponding program port number, and create an InetSocketAddress object InetSocketAddress address = new InetSocketAddress("192.168.31.154", 8848); // 4. Connect to the server if (!socket.connect(address)) { // If it is false, it means that the connection fails and the status of the application connection is maintained while (!socket.finishConnect()) { // Because NIO non blocking mode is adopted, other operations of the current program can be done in the state of obtaining waiting connection. System.out.println("Keep calling the server, but I can do something else~~~ Wait 2 s Continue to apply for connection~~~"); Thread.sleep(2000); } } // 5. Prepare a data buffer ByteBuffer buffer = ByteBuffer.wrap("Hello, server, I'm waiting for you...".getBytes()); // 6. Channel objects are sent through SocketChannel to meet the requirements of the TCP protocol Socket socket.write(buffer); new Scanner(System.in).nextLine(); } }
1.5.2 complete the server
1. Turn on the server ServerScoketChannel 2. open Selector Eldest brother Selector object 3. The server ServerSocketChannel bind port number 8848 port 4. Set non blocking status configureBlocking(false) 5. Selector register--> ServerSocketChannel register(selector, OP_ACCEPT); 6. Selector Big brother starts to work 6.1 Get the connection and register the corresponding Socket 6.2 Listen to read and write events 6.2.1 Read the data. Client sends data to server 6.2.2 Write data. Send data to client
package com.qfedu.a_tcpnio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; import java.util.Set; /** * Use ServerSocketChannel NIO non blocking mode to complete the server code * * 1. Turn on the server * ServerScoketChannel * 2. Open Selector * Selector object * 3. Server ServerSocketChannel bind listening port number * 8848 port * 4. Set non blocking status * configureBlocking(false) * 5. ServerSocketChannel Register -- > selector * register(selector, OP_ACCEPT); * * 6. Selector Big brother starts to work * 6.1 Get the connection and register the corresponding Socket * 6.2 Listen to read and write events * 6.2.1 Read the data. Client sends data to server * 6.2.2 Write data. Send data to client * * * @author Anonymous 2020/3/16 15:44 */ public class TcpNioServer { public static void main(String[] args) throws IOException { // 1. Turn on the server ServerSocketChannel serverSocket = ServerSocketChannel.open(); // 2. Open the Selector Selector selector = Selector.open(); // 3. Binding port number of server code serverSocket.bind(new InetSocketAddress(8848)); // 4. Set non blocking status serverSocket.configureBlocking(false); // 5. ServerSocketChannel registration - > the return value of selector is a SelectionKey // And make sure that the current Selector listens to selectionkey.op'u accept and listens to the connected server serverSocket.register(selector, SelectionKey.OP_ACCEPT); // 6. Big brother works while (true) { // 6.1 get the connection and register the corresponding Socket if (0 == selector.select(1000)) { // 0 == selector.select(1000) indicates no connection to the client System.out.println("ServerSocket Prompt: at present, there is no client to take care of me. I draw circles silently~~~"); continue; } // 6.2 listening to read / write events // Get all selectionkeys in the current Selector Iterator<SelectionKey> selectionKeys = selector.selectedKeys().iterator(); while (selectionKeys.hasNext()) { SelectionKey selectionKey = selectionKeys.next(); // 6.2.1 judge whether the client is a connection request OP? Accept if (selectionKey.isAcceptable()) { System.out.println("Client requests connection!!!"); // Get the corresponding Socket, but here is to get the corresponding SocketChannel SocketChannel socket = serverSocket.accept(); // Set the SocketChannel object of the current corresponding client to a non blocking state socket.configureBlocking(false); /* Register the current Socket object selector Register to the current Selector core SelectionKey.OP_READ Select the operation content monitored by the current Socket to read the data from the current Socket ByteBuffer.allocate(1024 * 4) attachment Supplementary parameter, here is to give the current Socket object a 4KB byte buffer object */ socket.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024 * 4)); } // 6.2.2 judge whether the client is in a readable state, and obtain the data sent by the client to the server if (selectionKey.isReadable()) { // Get the corresponding SocketChannel object from SelectionKey SocketChannel socket = (SocketChannel) selectionKey.channel(); // Because NIO is used, involving Channel and ByteBuffer, the data is in the buffer ByteBuffer buffer = (ByteBuffer) selectionKey.attachment(); // Read data. Use SocketChannel to read data from ByteBuffer. socket.read(buffer); System.out.println("Client sends data:" + new String(buffer.array())); } // After processing, perform a remove current SelectionKey operation selectionKeys.remove(); } } } }
2. NIO completes a TCP chat room
2.1 NIO TCP chat client completed
package com.qfedu.b_niochat; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; /** * NIO The core code of non blocking TCP chat client * * @author Anonymous 2020/3/16 16:20 */ public class ChatClient { /** * Server IP address */ private static final String HOST = "192.168.31.154"; /** * Port number corresponding to server connection */ private static final int PORT = 8848; /** * Return NIO request is a scorechannel object */ private SocketChannel socket; /** * User name */ private String userName; /** * Client construction method, creating client object * * @param userName Specified user name */ public ChatClient(String userName) throws IOException, InterruptedException { // 1. Open SocketChannel socket = SocketChannel.open(); // 2. Set non blocking status socket.configureBlocking(false); // 3. Create the corresponding InetSocketAddress according to the specified HOST IP address and the corresponding PORT port number InetSocketAddress address = new InetSocketAddress(HOST, PORT); // 4. Connect to the server if (!socket.connect(address)) { // If you are not connected to the server, keep the requested connection while (!socket.finishConnect()) { System.out.println("Server request connection failed, waiting for 2 s Continue request connection..."); Thread.sleep(2000); } } this.userName = userName; System.out.println("Client " + userName + " Ready"); } /* Two methods need to be completed here: one is to send data to the server, and the other is to accept the data sent by the server */ /** * Send data to the server for broadcast message and group chat * * @param message Specified message */ public void sendMsg(String message) throws IOException { // Disconnect the server close if ("close".equals(message)) { socket.close(); return; } /* StringBuffer Thread safety, low efficiency StringBuilder Unsafe and efficient threads */ message = userName + ":" + message; ByteBuffer buffer = ByteBuffer.wrap(message.getBytes()); socket.write(buffer); } public void receiveMsg() throws IOException { // Prepare ByteBuffer ByteBuffer buffer = ByteBuffer.allocate(1024); int length = socket.read(buffer); if (length > 0) { System.out.println(new String(buffer.array())); } } }
2.2 completion of NiO TCP chat server
package com.qfedu.b_niochat;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
/**
-
NIO non blocking TCP chat server core code
-
@author Anonymous 2020/3/16 16:59
*/
public class ChatServer {/**
- Server core module, ServerSocketChannel
*/
private ServerSocketChannel serverSocket;
/**
- NIO Selector selector of server
*/
private Selector selector;
/**
- Specified port number of server listening service
*/
private static final int PORT = 8848;
/*
- Construction method
- Receiving method
- Sending method (broadcast)
- start the receive and send functions at the same time
*/
/**
-
Server construction method: open ServerSocketChannel, and at the same time, open Selector to register operation
-
@throws IOException exception
*/
public ChatServer() throws IOException {
//1. Start server socket server NiO server
serverSocket = ServerSocketChannel.open();//2. Start selector
selector = Selector.open();//3. Port binding
serverSocket.bind(new InetSocketAddress(PORT));//4. Choose NIO mode as non blocking state
serverSocket.configureBlocking(false);//5. Register SeverSocket and confirm that the current listening status is op ﹣ accept
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
}
/**
-
Server working method, specify client binding, data receiving and forwarding
*/
public void start(){
try {
while (true) {
if (0 == selector.select(2000)) {
System.out.println("the server silently waits for connection, no one accesses..." );
continue;
}/* selectedKeys: Get the corresponding SelectionKey Set collection of all current event operations */ Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); // 1. connection if (key.isAcceptable()) { // Connect the client and get the corresponding SocketChannel object SocketChannel socket = serverSocket.accept(); socket.configureBlocking(false); socket.register(selector, SelectionKey.OP_READ); // Broadcast on line broadcast(socket, socket.getRemoteAddress().toString() + "Online."); } // 2. Receive data forwarding if (key.isReadable()) { readMsg(key); } iterator.remove(); } }
} catch (IOException e) {
e.printStackTrace();
}
}
/**
-
Read data from the specified SelectionKey
-
@param key the SelectionKey that meets the requirements of op'read
*/
public void readMsg(SelectionKey key) throws IOException {
//Get the corresponding SocketChannel object according to the specified SelectionKey
SocketChannel socket = (SocketChannel) key.channel();//Create buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);
//Read data from buffer, return value type is the number of bytes read
int length = socket.read(buffer);//Because the read data may have a 0 condition
if (length > 0) {
String message = new String(buffer.array());// Broadcast data broadcast(socket, message);
}
}
/**
-
Broadcast method, which is to send messages in groups, but do not send them to yourself
-
@param self client currently sending data
-
@param message message
/
public void broadcast(SocketChannel self, String message) throws IOException {
/
Get all selectionkeys in the current Selector
The content registered in the Selector has the SelectionKey corresponding to SocketChannel
SelectionKey corresponding to ServerSocketChannel
*/
Set keys = selector.keys();//Traverse the entire SelectionKey Set collection
for (SelectionKey key : keys) {
//Get the Channel object corresponding to SelectionKey
SelectableChannel channel = key.channel();// First: the channel corresponds to a SocketChannel object, which is not the SocketChannel object of the currently sent message if (channel instanceof SocketChannel && !channel.equals(self)) { SocketChannel socketChannel = (SocketChannel) channel; // Create the corresponding ByteBuffer buffer according to the specified Byte type array ByteBuffer buffer = ByteBuffer.wrap(message.getBytes()); // send data socketChannel.write(buffer); }
}
}
public static void main(String[] args) throws IOException {
new ChatServer().start();
} - Server core module, ServerSocketChannel
}
2.3 NIO TCP chat client thread code implementation
package com.qfedu.b_niochat; import java.io.IOException; import java.util.Scanner; /** * Client thread code * * @author Anonymous 2020/3/16 17:37 */ public class ChatClientThread { public static void main(String[] args) throws IOException, InterruptedException { Scanner scanner = new Scanner(System.in); System.out.println("enter one user name:"); String userName = scanner.nextLine(); if (0 == userName.length()) { return; } ChatClient chatClient = new ChatClient(userName); // receive messages new Thread(() -> { while (true) { try { chatClient.receiveMsg(); Thread.sleep(2000); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }).start(); // send message while (scanner.hasNextLine()) { String msg = scanner.nextLine(); chatClient.sendMsg(msg); } } }