Netty的相关知识
1、Java BIO(传统的Java IO模型)的相关知识
BIO同步并阻塞(传统阻塞型),服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销。
![Image text](https://unpkg.zhimg.com/youthlql@1.0.0/netty/introduction/chapter_001/0003.png)
package BIO; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class BIOServer { public static void main(String[] args) throws IOException { /** * 线程池机制 * 思路: * 1、创建线程池 * 2、如果有客户端连接,就创建一个线程,与之通信 */ ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); // 创建ServerSocket ServerSocket serverSocket = new ServerSocket(6666); System.out.println("服务端启动了"); while (true) { // 监听,等待客户端连接 System.out.println("线程信息id = " + Thread.currentThread().getId() + " 名字 = " + Thread.currentThread().getName() + " 正在等待客户端连接..."); // 如果客户端一直未连接,服务端会阻塞在这里 final Socket socket = serverSocket.accept(); System.out.println("连接到一个客户端"); // 创建一个线程,与之通讯 cachedThreadPool.execute(new Runnable() { public void run() { // 与客户端进行通讯 handler(socket); } }); } } // 编写与客户端进行通讯的方法 public static void handler(Socket socket) { try { byte[] bytes = new byte[1024]; // 字节流 // 通过socket获取输入流 InputStream inputStream = socket.getInputStream(); // 循环读取客户发送的数据 while (true) { System.out.println("线程信息id = " + Thread.currentThread().getId() + " 名字 = " + Thread.currentThread().getName() + " read...."); int read = inputStream.read(bytes); if (read != -1) { // 输出客户端发送的数据 System.out.println(new String(bytes, 0, read)); } else { break; } } } catch (IOException e) { e.printStackTrace(); } finally { System.out.println("关闭Client的连接"); try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
BIO(blocking IO)同步阻塞IO的缺点
- 每个请求都需要创建独立的线程,与对应的客户端进行数据
Read
,业务处理,数据Write
。 - 当并发数较大时,需要创建大量线程来处理连接,系统资源占用较大。
- 连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在
Read
操作上,造成线程资源浪费
2、Java NIO
package NIO; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; public class NIOClient { public static void main(String[] args) throws Exception { // 得到一个网络通道 SocketChannel socketChannel = SocketChannel.open(); // 设置为非阻塞 socketChannel.configureBlocking(false); // 提供服务端的ip和端口号 InetSocketAddress inetSocketAddress = new InetSocketAddress("10.180.58.11", 6666); // 客户端连接服务器 if (!socketChannel.connect(inetSocketAddress)) { while (!socketChannel.finishConnect()) { System.out.println("因为连接需要时间,客户端不会阻塞,可以做其他工作."); } } // 若连接成功 String string = "Hello world!"; // wrap a byte array into a buffer ByteBuffer buffer = ByteBuffer.wrap(string.getBytes()); // 发送数据,将buffer中的数据写到channel socketChannel.write(buffer); // 将代码停在此处 System.in.read(); } }
package NIO; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; import java.util.Set; public class NIOServer { public static void main(String[] args) throws Exception{ // 创建ServerSocketChannel ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 将serverSocketChannel绑定到端口,在服务器端进行监听 serverSocketChannel.socket().bind(new InetSocketAddress(6666)); // 设置为非阻塞 serverSocketChannel.configureBlocking(false); // 创建一个选择器 Selector selector = Selector.open(); // 将serverSocketChannel 注册到selector,关心事件为accept serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); // 注册到selector的key的数量是 System.out.println("注册到selectionKey的数量为:" + selector.keys().size()); // 等待客户端连接 while (true) { // 等待1s,如果没有连接则返回 if (selector.select(1000) == 0) { System.out.println("服务器等待了1s,客户端无连接"); continue; } // 已有连接,获取selectionKey的集合(关注事件的集合) Set<SelectionKey> selectionKeySet = selector.selectedKeys(); System.out.println("selectionKeys数量 = " + selectionKeySet.size()); // 通过selectionKeys反向获取通道 Iterator<SelectionKey> iterator = selectionKeySet.iterator(); while (iterator.hasNext()) { SelectionKey selectionKey = iterator.next(); // 根据selectionKey 对应的通道发生的事件做相应的处理 if (selectionKey.isAcceptable()) { // OP_ACCEPT,存在客户端的连接 // 生成一个socketChannel SocketChannel socketChannel = serverSocketChannel.accept(); System.out.println("客户端连接成功,生成一个SocketChannel: " + socketChannel.hashCode()); // 将socketChannel设置为非阻塞 socketChannel.configureBlocking(false); // 将socketChannel注册 socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024)); System.out.println("客户端连接后,注册到selectionKey的数量为:" + selector.keys().size()); } if (selectionKey.isReadable()) { // 发生OP_READ // 反向获取channel SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); // 获取channel关联的buffer ByteBuffer buffer = (ByteBuffer) selectionKey.attachment(); // 读取socketChannel中的数据 写到buffer socketChannel.read(buffer); System.out.println("来自客户端 " + new String(buffer.array())); } // 事件处理后,手动从集合中移动当前的selectionKey,防止重复操作 iterator.remove(); } } } }
3、netty的群聊系统
4、netty的心脏检测机制
作者:Ryanjie
出处:http://www.cnblogs.com/ryanjan/
本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!
如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [推荐],谢谢!