当前位置:网站首页>Network programming NiO: Bio and NiO
Network programming NiO: Bio and NiO
2020-11-06 01:38:00 【itread01】
BIO
BIO(Blocking I/O), Synchronous blocking , The implementation mode is one connection, one thread , When there is a client connection , The server needs to assign a thread to it , If the connection does not do anything, it will cause unnecessary thread overhead .BIO It's traditional Java io Programming , Its related classes and interfaces are in java.io It's a bag .
BIO It is suitable for architectures with small and fixed number of connections , High requirements for server resources , yes JDK1.4 The only choice before , But the program is simple and easy to understand .
BIO Programming process
-
The server starts a SeverSocket
-
The client starts Socket Initiate communication with server , By default, the server needs to create a thread for each client to communicate with it
-
After the client initiates the request , First, ask the server whether there is a thread response , If not, they will wait or be rejected
-
If there is a thread response , The client thread will wait for the request to end , Go ahead and carry on
Simple code implementation
//BIO- Server side public class BIOSever { public static void main(String[] args) throws IOException { // stay BIO in , You can use thread pools to optimize ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); ServerSocket serverSocket = new ServerSocket(6666); System.out.println(" Server started "); while (true){ System.out.println(" Wait for the client to connect .....( Blocked )"); Socket socket = serverSocket.accept(); System.out.println(" Client connection "); cachedThreadPool.execute(new Runnable() { public void run() { handler(socket); } }); } } // From the customer service side socket Read data public static void handler(Socket socket){ try{ InputStream inputStream = socket.getInputStream(); byte[] b = new byte[1024]; while (true){ System.out.println(" Waiting for client input .....( Blocked )"); int read = inputStream.read(b); if (read != -1){ System.out.println(new String(b, 0, read)); }else { break; } } inputStream.close(); }catch (Exception e){ e.printStackTrace(); }finally { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
//BIO- Client public class BIOClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("localhost", 6666); OutputStream outputStream = socket.getOutputStream(); Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()){ String message = scanner.nextLine(); if ("exit".equals(message)) { break; } outputStream.write(message.getBytes()); } outputStream.close(); socket.close(); } }
BIO Problem analysis
As you can see from the code above BIO Two problems of programming :
-
When the server is listening to the client connection (serverSocket.accept()), The server is in a blocked state , Can't handle anything else
-
The server needs to create a thread for each client , Although thread pools can be used to optimize , But when the concurrency is large , Thread overhead is still high
-
When the connected client does not transfer data , The server will be blocked in read Operationally , Waiting for client input , This causes a waste of thread resources
NIO
From JDK1.4 Start ,java Provides a series of improved inputs / New features of output , Collectively referred to as NIO, Full name n For new I/O, It's synchronous and non blocking , So some people call it non-blocking I/O.NIO All the related classes are placed in java.nio Under a bag or its subpackage , And to the original java.io Many classes in the package have been rewritten .
NIO The three cores of
Buffer (Buffer)
NIO It's buffer oriented , Or block oriented programming . stay NIO Of IO In transit , The data will be read into the buffer first , Write from the buffer when needed , This reduces the number of direct reads and writes to the disk , Improved IO Transmission efficiency .
Buffer (buffer) It is essentially a block of memory that can read and write data , In other words, a certain storage space is reserved in the memory space , This storage space is used to buffer input and output data , This part of the reserved storage space is called buffer .
stay NIO In program , passageway channel Although responsible for data transmission , But both input and output data must go through the buffer buffer.
stay java in , Buffer related classes are in java.nio It's a bag , The top-level class is Buffer, It's an abstract class .
Buffer Class 4 An important attribute :
-
mark: Mark
-
position: Location , The index of the next element to be read or written , This value is changed every time the buffer is read or written , Prepare for your next reading and writing
-
limit: Represents the end of the buffer , You cannot read or write to a location in the buffer that exceeds the limit , And the limits are modifiable
-
capacity: Capacity , The maximum amount of data that the buffer can hold , This value is set when the buffer is created , And it can't be modified
Buffer Class common methods :
Buffer A common subclass of ( The biggest difference between them lies in the data type of the underlying implementation array ):
-
ByteBuffer: Store byte data in buffer
-
CharBuffer: Store character data in buffer
-
IntBuffer: Store integer data in buffer
-
ShortBuffer: Store short data in buffer
-
LongBuffer: Store long data in buffer
-
FloatBuffer: Store floating-point data in buffer
-
DoubleBuffer: Store double precision floating-point data in buffer
ByteBuffer
stay Buffer In all subclasses of , The most commonly used is still ByteBuffer, Its common method :
passageway (Channel)
stay NIO The data read and write between the server and the client in the program is not through the stream , It's about reading and writing through channels .
Channels are like streams , It's all for reading and writing , But there's also a difference between them :
-
The channel is bidirectional , You can read or write , And the flow is unidirectional , Can only read or write
-
Channels can be used to read and write data asynchronously
-
The channel can read data from the buffer , You can also write data to a buffer
java in channel The related classes of are in java.nio.channel It's a bag .Channel It's an interface , Its common implementation classes are :
-
FileChannel: Data reading and writing for files , Its real implementation class is FileChannelImpl
-
DatagramChannel: Used for UDP Reading and writing , Its real implementation class is DatagramChannelImpl
-
ServerSocketChannel: For monitoring TCP Connect , Whenever there is a client connection, a SocketChannel, The function is similar ServerSocket, Its real implementation class is ServerSocketChannelImpl
-
SocketChannel: Used for TCP Reading and writing , The function is similar to node flow +Socket, Its real implementation class is SocketChannelImpl
FileChannel
FileChannel It is mainly used for local files IO operation , Such as file copying, etc . Its common methods are :
There is an attribute in the file stream channel, It is empty by default , It can be done by getChanel() Method generates the corresponding FileChannel.
public FileChannel getChannel() { synchronized (this) { if (channel == null) { channel = FileChannelImpl.open(fd, path, false, true, append, this); } return channel; } } }
Here are the code examples used by the channel :
public class NIOChannel { public static void main(String[] args) throws IOException { } // Write data to the target file public static void writeFile() throws IOException{ String str = "Hello, gofy"; // Create a file output stream FileOutputStream fileOutputStream = new FileOutputStream("f:\\file.txt"); // Generate file channel according to file output stream FileChannel fileChannel = fileOutputStream.getChannel(); // Create a byte buffer , And convert the string into bytes and store it in ByteBuffer byteBuffer = ByteBuffer.allocate(1024); byteBuffer.put(str.getBytes()); // Be careful , When you need to write after saving , The buffer needs to be flipped byteBuffer.flip(); // Write buffer data to channel fileChannel.write(byteBuffer); // Close the file output stream ( This method also closes the channel ) fileOutputStream.close(); } // Read data from a file public static void readFile() throws IOException{ // Create file input stream File file = new File("f:\\file.txt"); FileInputStream fileInputStream = new FileInputStream(file); // Generate file channel according to file input stream FileChannel fileChannel = fileInputStream.getChannel(); // Create a byte buffer , The size is the file size ByteBuffer byteBuffer = ByteBuffer.allocate((int)file.length()); // Read channel data into buffer fileChannel.read(byteBuffer); // Again , When you need to take out all the data in the buffer after reading , The buffer needs to be flipped byteBuffer.flip(); System.out.println(new String(byteBuffer.array())); fileInputStream.close(); } // Transfer file data to another file public static void readAndWriteFile() throws IOException{ // Create file input stream and file output stream , And generate the corresponding channel FileInputStream fileInputStream = new FileInputStream("file1.txt"); FileChannel inputStreamChannel= fileInputStream.getChannel(); FileOutputStream fileOutputStream = new FileOutputStream("file2.txt"); FileChannel outputStreamChannel = fileOutputStream.getChannel(); // Create a byte buffer ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // Read the data while (true){ // Clear buffer before reading byteBuffer.clear(); // Read the data of the channel entered by the file into the buffer int read = inputStreamChannel.read(byteBuffer); // When read For -1 When , That is, the channel data has been read if (read == -1){ break; } // After flipping the buffer , Write buffer data to the file output channel byteBuffer.flip(); outputStreamChannel.write(byteBuffer); } fileInputStream.close(); fileOutputStream.close(); } // Copy the file and paste it public static void copyAndPaste() throws IOException{ // Copied file input stream FileInputStream fileInputStream = new FileInputStream("f:\\a.jpg"); FileChannel srcChannel = fileInputStream.getChannel(); // Pasted file output stream FileOutputStream fileOutputStream = new FileOutputStream("f:\\b.jpg"); FileChannel targetChannel = fileOutputStream.getChannel(); // Use transferFrom Copy and paste targetChannel.transferFrom(srcChannel, 0, srcChannel.size()); fileInputStream.close(); fileOutputStream.close(); } }
Selectors (Selector)
stay NIO In program , You can use a selector Selector Implement a selector to handle multiple channels , That is, a thread processes multiple connections . Just register the channel to Selector On , You can go through Selector To monitor the channel , If something happens to the channel , Then get the event channel and process each event accordingly . So , Only in the passage ( Connect ) There's real reading / Write about when the event happened , Then read and write , Greatly reduces system overhead , And you don't have to create a separate thread for each connection , You don't have to maintain too many threads .
The relevant class of the selector is in java.nio.channels Under the bag and its subpackages , The top class is Selector, It's an abstract class , Its common methods are :
Channel registration
stay ServerSocketChannel and SocketChannel Class has a registration method register(Selector sel, int ops),sel For the selector to register with ,ops The type of operation event that is monitored for this channel , You can use this method to ServerSocketChannel or SocketChannel Register in the target selector , This method returns a SelectionKey( The real implementation class is SelectionKeyImpl) Stored in the registered Selector Of publicKeys Set attribute .SelectionKey Stores the event type of the channel and the registered channel object , It can be done by SelectionKey.channel() Method to get SelectionKey The corresponding channel .
Each channel registered to the selector needs to define the type of operation event to be performed , By examining SelectionKey Class property can know that the type of operation event is 4 Species :
public static final int OP_READ = 1 << 0; // Read operation public static final int OP_WRITE = 1 << 2; // Write operation public static final int OP_CONNECT = 1 << 3; // Connection operation public static final int OP_ACCEPT = 1 << 4; // Receive operation
Check the selector
We can go through the selector check method , Such as select() To find out the number of channels that have happened , When the quantity is greater than 0 When , That is, at least one channel has an event , You can use selectedKeys() Method to get the corresponding channel of all events SelectionKey, Through SelectionKey To determine the type of event to be processed in the corresponding channel , According to the event to make the corresponding processing .
public final boolean isReadable() { // Determine whether it is a read operation return (readyOps() & OP_READ) != 0; } public final boolean isWritable() { // Determine whether it is a write operation return (readyOps() & OP_WRITE) != 0; } public final boolean isConnectable() { // Determine whether it is a connection operation return (readyOps() & OP_CONNECT) != 0; } public final boolean isAcceptable() { // Determine whether it is a receive operation return (readyOps() & OP_ACCEPT) != 0; }
NIO Realize simple chat group
// Server side public class GroupChatSever { private final static int PORT = 6666;// Monitor port private Selector selector;// Selectors private ServerSocketChannel serverSocketChannel; public GroupChatSever(){ try{ selector = Selector.open();// Turn on the selector serverSocketChannel = ServerSocketChannel.open();// Open the channel serverSocketChannel.configureBlocking(false);// Set the channel to a non blocking state serverSocketChannel.socket().bind(new InetSocketAddress(PORT));// Channel binding listening port serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// Register channel to selector , The event type is receive listen(); }catch (IOException e){ e.printStackTrace(); } } // Monitoring ports public void listen(){ try { while (true){ // Check the registration channel for events , The inspection time is 2 second int count = selector.select(2000); if (count > 0){// If an event occurs in the registration channel, it will be handled // Get the corresponding channel of all events SelectionKey Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator(); while (keyIterator.hasNext()){ SelectionKey key = keyIterator.next(); if (key.isAcceptable()){// Judge what should be key Whether the corresponding channel needs receiving operation // Although accept() Method is blocked , But because the channel has been judged , // It can be confirmed that there is a client connection , So this is the call accept It doesn't block SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); // After receiving , Register the acquired client channel to the selector , The event type is read socketChannel.register(selector, SelectionKey.OP_READ); System.out.println(socketChannel.getRemoteAddress() + " Online !"); } if (key.isReadable()){// Judge what should be key Whether the corresponding channel needs to be read readFromClient(key); } // Notice that when you're done with a channel key When , It needs to be removed from the iterator keyIterator.remove(); } } } }catch (IOException e){ e.printStackTrace(); } } /** * Read the message from the client * @param key Corresponding to the channel to be read SelectionKey */ public void readFromClient(SelectionKey key){ SocketChannel socketChannel = null; try{ // Through SelectionKey Get the corresponding channel socketChannel = (SocketChannel)key.channel(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); int read = socketChannel.read(byteBuffer); if (read > 0){ String message = new String(byteBuffer.array()); System.out.println(" Client : " + message); sendToOtherClient(message, socketChannel); } }catch (IOException e){ // It's simplified here , Treat all exceptions as exceptions triggered by client disconnection , Please do not do this in actual projects try{ System.out.println(socketChannel.getRemoteAddress() + " Offline "); key.cancel();// Will be SelectionKey Withdraw socketChannel.close();// Then close the corresponding channel }catch (IOException e2){ e2.printStackTrace(); } } } /** * Forward the message sent by the client to other clients * @param message Forward message * @param from The client channel for sending messages * @throws IOException */ public void sendToOtherClient(String message, SocketChannel from) throws IOException{ System.out.println(" Message forwarding ......"); for (SelectionKey key : selector.keys()){// Traverse all the... In the selector SelectionKey Channel channel = key.channel();// According to SelectionKey Get the corresponding channel // Get rid of channels that send messages , Write messages to other client channels if (channel instanceof SocketChannel && channel != from){ SocketChannel socketChannel = (SocketChannel)channel; ByteBuffer byteBuffer = ByteBuffer.wrap(message.getBytes()); socketChannel.write(byteBuffer); } } } public static void main(String[] args) { GroupChatSever groupChatSever = new GroupChatSever(); } }
// Client public class GroupChatClient { private final static String SEVER_HOST = "127.0.0.1";// Connected client host private final static int SEVER_PORT = 6666;// The client port of the connection private Selector selector;// Selectors private SocketChannel socketChannel; private String username;// Storage client ip Address public GroupChatClient(){ try { selector = Selector.open();// Turn on the selector socketChannel = SocketChannel.open(new InetSocketAddress(SEVER_HOST, SEVER_PORT));// Open the channel socketChannel.configureBlocking(false);// Set the channel to non blocking socketChannel.register(selector, SelectionKey.OP_READ);// Register the channel on the selector , The event type is read username = socketChannel.getLocalAddress().toString().substring(1);// Get the client ip Address String message = " Join the chat group !"; sendMessage(message); }catch (IOException e){ e.printStackTrace(); } } // Send a message public void sendMessage(String message){ message = username+": "+message; try{ ByteBuffer byteBuffer = ByteBuffer.wrap(message.getBytes()); socketChannel.write(byteBuffer); }catch (IOException e){ e.printStackTrace(); } } // Read messages forwarded from the server public void readMessage(){ try{ int read = selector.select(); if (read > 0){ Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator(); while (keyIterator.hasNext()){ SelectionKey key = keyIterator.next(); if (key.isReadable()){ SocketChannel socketChannel = (SocketChannel)key.channel(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); socketChannel.read(byteBuffer); System.out.println(new String(byteBuffer.array())); } keyIterator.remove(); } } }catch (IOException e){ e.printStackTrace(); } } public static void main(String[] args) { final GroupChatClient groupChatClient = new GroupChatClient(); // The client opens a thread to listen for messages from the server new Thread(){ @Override public void run() { while (true){ groupChatClient.readMessage(); try { Thread.currentThread().sleep(1000); }catch (InterruptedException e){ e.printStackTrace(); } } } }.start(); Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()){ String message = scanner.nextLine(); groupChatClient.sendMessage(message); } } }
&n
版权声明
本文为[itread01]所创,转载请带上原文链接,感谢
边栏推荐
- Wechat applet: prevent multiple click jump (function throttling)
- 仅用六种字符来完成Hello World,你能做到吗?
- 前端工程师需要懂的前端面试题(c s s方面)总结(二)
- 使用 Iceberg on Kubernetes 打造新一代雲原生資料湖
- 一篇文章带你了解CSS对齐方式
- 用一个例子理解JS函数的底层处理机制
- Cglib 如何实现多重代理?
- Free patent download tutorial (HowNet, Espacenet)
- I'm afraid that the spread sequence calculation of arbitrage strategy is not as simple as you think
- Jmeter——ForEach Controller&Loop Controller
猜你喜欢
How to encapsulate distributed locks more elegantly
Recommendation system based on deep learning
只有1个字节的文件实际占用多少磁盘空间
It is really necessary to build a distributed ID generation service
Python基础数据类型——tuple浅析
Custom function form of pychar shortcut key
理解格式化原理
Jetcache buried some of the operation, you can't accept it
Using NLP and ml to extract and construct web data
Summary of common string algorithms
随机推荐
Mac installation hanlp, and win installation and use
5.5 controlleradvice notes - SSM in depth analysis and project practice
Brief introduction of TF flags
游戏主题音乐对游戏的作用
How to encapsulate distributed locks more elegantly
每个大火的“线上狼人杀”平台,都离不开这个新功能
[event center azure event hub] interpretation of error information found in event hub logs
I think it is necessary to write a general idempotent component
理解格式化原理
仅用六种字符来完成Hello World,你能做到吗?
Discussion on the technical scheme of text de duplication (1)
Simple summary of front end modularization
Cglib 如何实现多重代理?
It's easy to operate. ThreadLocal can also be used as a cache
快速排序为什么这么快?
有了这个神器,快速告别垃圾短信邮件
Analysis of ThreadLocal principle
Construction of encoder decoder model with keras LSTM
ES6学习笔记(五):轻松了解ES6的内置扩展对象
使用 Iceberg on Kubernetes 打造新一代雲原生資料湖