学习笔记一: 基于JavaNIO和线程池实现简单的TCP服务器
概念(个人的理解):
OIO/BIO:阻塞式同步IO,程序向操作系统发出IO指令,程序等待操作系统返回数据,面向流的编程模式
NIO:非阻塞式同步IO,程序向操作系统发出IO请求,操作系统将请求注册,将就绪的IO指令注册在链表上,程序通过系统调用轮询链表,面向channel和buffer的编程模式
AIO:非阻塞异步IO,程序向操作系统发出IO指令继续往下执行,操作系统处理IO请求后通知应用程序处理
Linux的epoll机制(个人简单理解)
程序是对内存进行操作,而epoll提供3个函数供系统调用
epoll_create是创建一个epoll句柄;(程序通过该系统调用创建了一块内存地址)
epoll_ctl是注册要监听的事件类型;(程序通过系统调用修改这块内存地址信息)
epoll_wait则是等待事件的产生。(程序通过系统调用遍历这块内存地址,获得到来的读写事件)
实现思路:
1.server控制类:TCP服务器启动关闭
2.server类:包括socketChannel注册读事件,channel数据读取到channel为key的map中
3.读线程类:读取map调用线程池处理具体数据
4.处理数据类:
5.线程池类:基于JDK自带的线程池
server控制类:
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
@Getter
@Setter
public class ServerManager implements DisposableBean, InitializingBean {
private NIOTCPServer niotcpServer;
@Override
public void destroy() throws Exception {
stop();
}
@Override
public void afterPropertiesSet() throws Exception {
if (this.niotcpServer == null){
this.niotcpServer = new NIOTCPServer();
this.niotcpServer.afterPropertiesSet();
}
}
/**
* 启动
*/
public void start(){
this.niotcpServer.start();
}
/**
* 停止
*/
public void stop(){
this.niotcpServer.shutdown();
}
}
server线程
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import sun.nio.ch.DirectBuffer;
import java.io.IOException;
import java.net.BindException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
@Setter
@Getter
public class NIOTCPServer extends Thread implements InitializingBean {
private static Logger logger = LoggerFactory.getLogger(NIOTCPServer.class);
private int port = 8080;
private boolean configureBlocking;
private boolean throwBindException;
private ServerSocketChannel serverSocketChannel;
private final Object dataLock = new Object();
private volatile boolean stopFlag;
private ReadThread readThread;
private ByteBuffer byteBuffer;
@Override
public void afterPropertiesSet() throws Exception {
this.serverSocketChannel = ServerSocketChannel.open();
this.serverSocketChannel.configureBlocking(this.configureBlocking);