什么是netty
- 由jboss提供的一个java开源项目
- 是一个异步的、基于事件驱动的网络应用框架,用于快速开发高并发、高可靠的网络IO程序
- 主要针对TCP协议下,面向Clients端的高并发,或者Peer-toPeer场景下的大量数据持续输出的应用
- 本质是一个NIO,适用于服务器通信相关的多种应用场景
- 层级与结构
TCP/IP |
---|
原生的JDK(IO/网络) => java的io原理和网络编程原理 |
NIO(IO、网络) |
Netty |
应用场景
- 互联网行业、分布式,阿里Dubbo的RPC框架的使用
- 游戏行业(网络游戏)、地图与服务器之间的通信
- 大数据领域 AVRO 实现数据文件共享
IO模型
-
理解:用什么样的通道进行数据发送和接受,很大程度上决定了程序通信的性能
-
java支持3种网络编程模型:BIO、NIO、AIO
-
BIO:一个连接对应一个线程(同步阻塞型)
-
NIO:同步非阻塞型
-
AIO:异步非阻塞型 (没有得到广泛使用)
-
三种io模型的使用场景
BIO的工作机制
- 流程
- 服务器端启动一个ServerSocket
- 客户端启动Socket对服务进行通信,默认情况下服务器端需要对每个客户建立一个线程与之通信
- 客户端发出请求后,先咨询服务器是否有线程响应,如果没有则会等待,或者被拒绝
- 如果有响应,客户端线程会等待请求结束后,再继续执行
线程池的7种创建方法
1. Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池,可控制并发的线程数,
超出的线程会在队列中等待;
2. Executors.newCachedThreadPool:创建⼀个可缓存的线程池,若线程数超过处理所
需,缓存⼀段时间后会回收,若线程数不够,则新建线程;
3. Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先
出的执⾏顺序;
4. Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池;
5. Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执⾏延迟任
务的线程池;
6. Executors.newWorkStealingPool:创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确
定)【JDK1.8 添加】。
7. ThreadPoolExecutor:最原始的创建线程池的⽅式,它包含了 7 个参数可供设置
案例
指令
- telnet 127.0.0.1:6666 指定连接
- ctrl+] 客户端输入信息
- send + 你要输入的信息 (例如: send hello netty )
解答
思路:
- 创建一个线程池
- 如果有客户端连接,就创建一个线程,与之通信(单独写一个方法
public class BIOServer {
public static void main(String[] args) throws IOException {
ExecutorService servicePool = Executors.newCachedThreadPool();
// 创建ServerSocket
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("服务器启动了");
while(true) {
System.out.println("线程信息"+Thread.currentThread().getId()+"线程
名"+Thread.currentThread().getName());
// 监听客户端连接
System.out.println("等待连接");
final Socket socket = serverSocket.accept();
System.out.println("没有连接就会阻塞在上一步,有连接就会打印这句话======》连接到一个客户端");
// 创建一个线程,与之同行独立写一个方法
servicePool.execute(new Runnable() {
@Override
public void run() {
// 可与客户端进行通信
hander(socket);
} });
}
}
public static void hander(Socket socket) {
System.out.println("线程信息"+Thread.currentThread().getId()+"线程名"+Thread.currentThread().getName());
byte [] bytes = new byte[1024];
// 通过socket获取输入流
InputStream inputStream = null;
try {
inputStream = socket.getInputStream();
// 循环读取客户端发送的数据
while(true) {
System.out.println("线程信息"+Thread.currentThread().getId()+"线程名"+Thread.currentThread().getName());
System.out.println("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 {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果