一、BIO 阻塞IO
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9000);
while(true){
Socket socket = serverSocket.accept();
System.out.println("somebody connected");
handler(socket);
socket.close();
}
}
public static void handler(Socket socket) {
int value = 0;
try {
value = socket.getInputStream().read();
while (value != -1) {
System.out.println(value);
value = socket.getInputStream().read();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
二、NIO 非阻塞IO
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;
public class NioSelectServer {
static List<SocketChannel> channelList = new ArrayList<>();
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9000));
serverSocketChannel.configureBlocking(false);
while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
if(null != socketChannel){
//someone connected
socketChannel.configureBlocking(false);
channelList.add(socketChannel);
}
for (SocketChannel channel : channelList) {
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
int len = channel.read(byteBuffer);
if(len == -1){
channelList.remove(channel);
}else if(len !=0){
System.out.println(new String(byteBuffer.array()));
}
}
}
}
}
三、NIO Selector
import java.io.IOException;
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.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class NioSelectorServer {
static List<SocketChannel> channelList = new ArrayList<>();
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9000));
serverSocketChannel.configureBlocking(false);
//打开selector,注册channel即创建epoll(create ctl )
Selector selector = Selector.open();
SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
//阻塞等待事件的触发
selector.select();
//获取所有触发的事件
Set<SelectionKey> selectionKeys = selector.keys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()){
SelectionKey key = iterator.next();
if(key.isAcceptable()){
ServerSocketChannel server = (ServerSocketChannel)key.channel();
SocketChannel socketChannel = server.accept();
if(null != socketChannel){
socketChannel.configureBlocking(false);
socketChannel.register(selector,SelectionKey.OP_READ);
System.out.println("连接成功");
}
}else if(key.isReadable()){
SocketChannel socketChannel = (SocketChannel)key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(128);
int len = socketChannel.read(byteBuffer);
if(len > 0){
System.out.println(new String(byteBuffer.array()));
}else if(len == -1){
System.out.println("disconnected");
socketChannel.close();
}
}
}
}
}
}
四、epoll模型
epoll模型由三个指令组成epoll_create、epoll_ctl、epoll_wait,分别表示创建描述符、注册描述符事件、阻塞等待事件触发
epoll的底层是一个红黑树存储描述符,在epoll_ctl的时候把描述符存到内核态空间,并设置一个回调任务,当该描述符有对应事件的时候,会把注册的对象和对应的事件写到待处理列表,然后epoll_wait会定时读取这个列表,有数据的话就会返回
特点:
1、epoll的数据是通过dmmp直接在用户态跟内核态共享内存,速度很快
2、epoll有两种模式,一种是数据没有读取完毕就会通知(会导致事件过多),第二种是只通知一次,需要把数据全读取完毕