java NIO
nio三剑客
buffer三剑客
多路复用的范式
server
package com.deppyu.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
/**
* @author deppyu
* @date 2019-08-12 12:46
*/
public class NioServerDemo {
volatile static Map<Integer , String> keyAndName = new HashMap<>(4);
static{
keyAndName.put(SelectionKey.OP_CONNECT , "OP_CONNECT");
keyAndName.put(SelectionKey.OP_ACCEPT , "OP_ACCEPT");
keyAndName.put(SelectionKey.OP_READ , "OP_READ");
keyAndName.put(SelectionKey.OP_WRITE , "OP_WRITE");
System.out.println(keyAndName);
}
public volatile static Map<String,SocketChannel> connStore = new HashMap<String, SocketChannel>(16);
public static List<SocketAddress> getSocketAddressList(){
List<SocketAddress> socketAddresses = new ArrayList<>(4);
socketAddresses.add(new InetSocketAddress(5566));
// socketAddresses.add(new InetSocketAddress(7788));
// socketAddresses.add(new InetSocketAddress(1234));
return socketAddresses;
}
public static String getOpeNameById(Integer key){
return keyAndName.get(key);
}
public static void main(String[] args) throws IOException {
List<SocketAddress> socketAddresses = getSocketAddressList();
Selector selector = Selector.open();
for(SocketAddress socketAddress : socketAddresses){
// 这个是等待可用请求的channel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocket.bind(socketAddress);
// accept()函数功能是,从处于 established 状态的连接队列头部取出一个已经完成的连接,如果这个队列没有已经完成的连接,accept()函数就会阻塞,直到取出队列中已完成的用户连接为止。
// serverSocketChannel关注的是连接事件
serverSocketChannel.register(selector , SelectionKey.OP_ACCEPT);
}
while(true){
System.out.println("阻塞等待新的事件到来-> ...");
selector.select();
Set<SelectionKey> selectionKeySet = selector.selectedKeys();
//同一个端口的连接事件 即便多次 都对应同一个selectKey
System.out.println("selector中的事件数量=" + selectionKeySet.size());
for(SelectionKey selectionKey : selectionKeySet){
System.out.println("行为=" + getOpeNameById(selectionKey.interestOps()) + selectionKey.toString());
}
Iterator<SelectionKey> iterator = selectionKeySet.iterator();
while (iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
try{
if(selectionKey.isAcceptable()){
SelectableChannel selectableChannel = selectionKey.channel();
ServerSocketChannel serverSocketChannel = (ServerSocketChannel)selectableChannel;
//阻塞的等待连接建立好,这里的channel可以理解成是一种连接
SocketChannel socketChannel = serverSocketChannel.accept();
if(socketChannel!=null){
socketChannel.configureBlocking(false);
//此处的socketChannel关注的是读取数据事件
socketChannel.register(selector , SelectionKey.OP_READ);
String key = "user-"+UUID.randomUUID().toString();
System.out.println("key->" + key + " channel->[" + socketChannel + "]上线");
connStore.put(key , socketChannel);
}
}else if(selectionKey.isReadable()){
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
while(true){
byteBuffer.clear();
SocketChannel channel = (SocketChannel)selectionKey.channel();
byteBuffer.put("->".getBytes());
int length = channel.read(byteBuffer);
if(length <= 0){
break;
}
for(Map.Entry<String,SocketChannel> entry : connStore.entrySet()){
byteBuffer.flip();
entry.getValue().write(byteBuffer);
}
}
}
}finally {
iterator.remove();
}
}
}
}
}
client
package com.deppyu.nio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author deppyu
* @date 2019-08-12 21:15
*/
public class NioClientDemo {
static ExecutorService executorService = Executors.newSingleThreadExecutor();
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(5566));
System.out.println("原始channel->"+socketChannel);
Selector selector = Selector.open();
socketChannel.register(selector , SelectionKey.OP_CONNECT);
while(true){
selector.select();
Set<SelectionKey> selectionKeySet = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeySet.iterator();
while(iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
if(selectionKey.isConnectable()){
SocketChannel channel = (SocketChannel)selectionKey.channel();
System.out.println("isConnectionPending ->" + channel.isConnectionPending());
if(channel.isConnectionPending()){
channel.finishConnect();
}
channel.register(selector , SelectionKey.OP_READ);
executorService.submit(new Runnable() {
@Override
public void run() {
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
while(true){
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
try {
String message = bufferedReader.readLine();
byteBuffer.clear();
byteBuffer.put(message.getBytes());
byteBuffer.flip();
channel.write(byteBuffer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}else if(selectionKey.isReadable()){
SocketChannel socketChannelRead = (SocketChannel)selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
while(true){
byteBuffer.clear();
int length = socketChannelRead.read(byteBuffer);
if(length<=0){
break;
}
String msgReceived = new String(byteBuffer.array() , 0 , length);
System.out.println("收到的服务器的消息->"+msgReceived);
}
}
iterator.remove();
}
}
}
}
netty的reactor模式