当前位置:网站首页>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]所创,转载请带上原文链接,感谢
边栏推荐
- React design pattern: in depth understanding of react & Redux principle
- 小游戏云开发入门
- C#和C/C++混合编程系列5-内存管理之GC协同
- Natural language processing - BM25 commonly used in search
- With the advent of tensorflow 2.0, can pytoch still shake the status of big brother?
- 一篇文章带你了解HTML表格及其主要属性介绍
- 前端都应懂的入门基础-github基础
- 游戏主题音乐对游戏的作用
- TensorFlow中的Tensor是什么?
- 一部完整的游戏,需要制作哪些音乐?
猜你喜欢
Using NLP and ml to extract and construct web data
JVM memory area and garbage collection
Did you blog today?
The dynamic thread pool in Kitty supports Nacos and Apollo multi configuration centers
Unity性能优化整理
一篇文章教会你使用HTML5 SVG 标签
Flink的DataSource三部曲之一:直接API
Thoughts on interview of Ali CCO project team
Wow, elasticsearch multi field weight sorting can play like this
一路踩坑,被迫聊聊 C# 代码调试技巧和远程调试
随机推荐
一路踩坑,被迫聊聊 C# 代码调试技巧和远程调试
Architecture article collection
For a while, a dynamic thread pool was created, and the source code was put into GitHub
Arrangement of basic knowledge points
快速排序为什么这么快?
一篇文章教会你使用Python网络爬虫下载酷狗音乐
Installing ns-3 on ubuntu18.04
Electron application uses electronic builder and electronic updater to realize automatic update
Using NLP and ml to extract and construct web data
6.6.1 localeresolver internationalization parser (1) (in-depth analysis of SSM and project practice)
有了这个神器,快速告别垃圾短信邮件
Chainlink brings us election results into blockchain everipedia
What problems can clean architecture solve? - jbogard
只有1个字节的文件实际占用多少磁盘空间
Python基础数据类型——tuple浅析
Pollard's Rho algorithm
Network security engineer Demo: the original * * is to get your computer administrator rights! [maintain]
每个大火的“线上狼人杀”平台,都离不开这个新功能
I think it is necessary to write a general idempotent component
Recommendation system based on deep learning