传统Socket / OIO
1 public class OioServer {
2
3 @SuppressWarnings("resource")
4 public static void main(String[] args) throws Exception {
5
6 ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
7 //创建socket服务,监听10101端口
8 ServerSocket server=new ServerSocket(10101);
9 System.out.println("服务器启动!");
10 while(true){
11 //获取一个套接字(阻塞)
12 final Socket socket = server.accept();
13 System.out.println("来个一个新客户端!");
14 newCachedThreadPool.execute(new Runnable() {
16 @Override
17 public void run() {
18 //业务处理
19 handler(socket);
20 }
21 });
23 }
24 }
25
26 /**
27 * 读取数据
28 * @param socket
29 * @throws Exception
30 */
31 public static void handler(Socket socket){
32 try {
33 byte[] bytes = new byte[1024];
34 InputStream inputStream = socket.getInputStream();
35
36 while(true){
37 //读取数据(阻塞)
38 int read = inputStream.read(bytes);
39 if(read != -1){
40 System.out.println(new String(bytes, 0, read));
41 }else{
42 break;
43 }
44 }
45 } catch (Exception e) {
46 e.printStackTrace();
47 }finally{
48 try {
49 System.out.println("socket关闭");
50 socket.close();
51 } catch (IOException e) {
52 e.printStackTrace();
53 }
54 }
55 }
56 }
缺点
单线程情况下只能有一个客户端
用线程池可以有多个客户端连接,但是非常消耗性能
类比图
public class NIOServer {
2
// 通道管理器
3 private Selector selector;
5 /**
6 * 获得一个ServerSocket通道,并对该通道做一些初始化的工作
7 *
8 * @param port
9 * 绑定的端口号
10 * @throws IOException
11 */
12 public void initServer(int port) throws IOException {
13 // 获得一个ServerSocket通道
14 ServerSocketChannel serverChannel = ServerSocketChannel.open();
15 // 设置通道为非阻塞
16 serverChannel.configureBlocking(false);
17 // 将该通道对应的ServerSocket绑定到port端口
18 serverChannel.socket().bind(new InetSocketAddress(port));
19 // 获得一个通道管理器
20 this.selector = Selector.open();
21 // 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
22 // 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
23 serverChannel.register(selector, SelectionKey.OP_ACCEPT);
24 }
25
26 /**
27 * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
28 *
29 * @throws IOException
30 */
31 public void listen() throws IOException {
32 System.out.println("服务端启动成功!");
33 // 轮询访问selector
34 while (true) {
35 // 当注册的事件到达时,方法返回;否则,该方法会一直阻塞
36 selector.select();
37 // 获得selector中选中的项的迭代器,选中的项为注册的事件
38 Iterator
优点
利用Selector多路复用技术, 一个线程可以处理多个客户端.
类比图
Netty Server