当前位置:网站首页>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]所创,转载请带上原文链接,感谢
边栏推荐
- Analysis of etcd core mechanism
- Chainlink brings us election results into blockchain everipedia
- 前端未來趨勢之原生API:Web Components
- [JMeter] two ways to realize interface Association: regular representation extractor and JSON extractor
- 给字节的学姐讲如何准备“系统设计面试”
- Analysis of partial source codes of qthread
- C + + and C + + programmers are about to be eliminated from the market
- Shh! Is this really good for asynchronous events?
- ES6学习笔记(五):轻松了解ES6的内置扩展对象
- 【自学unity2d传奇游戏开发】如何让角色动起来
猜你喜欢

百万年薪,国内工作6年的前辈想和你分享这四点

How to encapsulate distributed locks more elegantly

Three Python tips for reading, creating and running multiple files
![[JMeter] two ways to realize interface Association: regular representation extractor and JSON extractor](/img/cc/17b647d403c7a1c8deb581dcbbfc2f.jpg)
[JMeter] two ways to realize interface Association: regular representation extractor and JSON extractor

零基础打造一款属于自己的网页搜索引擎

Elasticsearch数据库 | Elasticsearch-7.5.0应用搭建实战

In order to save money, I learned PHP in one day!

Pattern matching: The gestalt approach一种序列的文本相似度方法

01. SSH Remote terminal and websocket of go language

Who says cat can't do link tracking? Stand up for me
随机推荐
What is the side effect free method? How to name it? - Mario
零基础打造一款属于自己的网页搜索引擎
Python基础变量类型——List浅析
一路踩坑,被迫聊聊 C# 代码调试技巧和远程调试
I'm afraid that the spread sequence calculation of arbitrage strategy is not as simple as you think
理解格式化原理
ES6学习笔记(二):教你玩转类的继承和类的对象
Humor: hacker programming is actually similar to machine learning!
一篇文章带你了解CSS3圆角知识
NLP model Bert: from introduction to mastery (2)
Interpretation of Cocos creator source code: engine start and main loop
【自学unity2d传奇游戏开发】如何让角色动起来
I've been rejected by the product manager. Why don't you know
Unity性能优化整理
DRF JWT authentication module and self customization
带你学习ES5中新增的方法
仅用六种字符来完成Hello World,你能做到吗?
每个前端工程师都应该懂的前端性能优化总结:
Who says cat can't do link tracking? Stand up for me
Shh! Is this really good for asynchronous events?