NIO通讯Client端
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.SocketChannel;
import java.util.Iterator;
public class NIOClient{
public static void main(String[] args)
{
for (int i = 0; i < 10; i++) {
new Worker().start();
}
}
static class Worker extends Thread {
@Override
public void run(){
SocketChannel channel = null;
Selector selector = null;
try{
//SocketChannel,一看底层就是封装了一个Socket
channel = SocketChannel.open();
//SocketChannel是连接到底层的Socket网络
//数据通道就是负责基于网络读写数据的
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("localhost",9000));
//后台一定是tcp三次握手建立网络连接
selector = Selector.open();
// 监听Connect这个行为
channel.register(selector,SelectionKey.OP_CONNECT);
while (true) {
//selector多路复用机制的实现 循环去遍历各个注册的Channel
selector.select();
Iterator<SelectionKey> keysIterator = selector.selectedKeys().iterator();
while (keysIterator.hasNext()) {
SelectionKey key = (SelectionKey) keysIterator.next();
keysIterator.remove();
//如果发现返回的时候一个可连接的消息 走到下面去接受数据
if (key.isConnectable()) {
channel = (SocketChannel) key.channel();
if (channel.isConnectionPending()) {
channel.finishConnect();
//接下来对这个SocketChannel感兴趣的就是人家server给你发送过来的数据了
//READ事件,就是可以读数据的事件
//一旦建立连接成功了以后,此时就可以给server发送一个请求了
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("你好".getBytes());
buffer.flip();
channel.write(buffer);
}
channel.register(selector,SelectionKey.OP_READ);
}
//这里的话就时候名服务器端返回了一条数据可以读了
else if (key.isReadable()) {
channel = (SocketChannel) key.channel();
//构建一个缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
//把数据写入buffer,position推进到读取的字节数数字
int len = channel.read(buffer);
if (len > 0){
System.out.println("["+Thread.currentThread().getName()+"]收到响应:"
+new String(buffer.array(),0, len));
Thread.sleep(5000);
channel.register(selector,SelectionKey.OP_WRITE);
}
}else if (key.isWritable()){
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("你好".getBytes());
buffer.flip();
channel = (SocketChannel) key.channel();
channel.write(buffer);
channel.register(selector,SelectionKey.OP_READ);
}
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel != null) {
try{
channel.close();
}catch(IOException e)
{
e.printStackTrace();
}
} if (selector != null) {
try{
selector.close();
}catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
}
NIO通讯Server端
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
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.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class NIOServer {
private static Selector selector;
private static LinkedBlockingQueue<SelectionKey> requestQueue;
private static ExecutorService threadPool;
public static void main(String[] args){
init();
listen();
}
private static void init() {
ServerSocketChannel serverSocketChannel = null;
try{
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
//将Channel设置为非阻塞的 NIO就是支持非阻塞的
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(9000),100);
//ServerSocket,就是负责去跟各个客户端连接连接请求的
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
//就是仅仅关注这个ServerSocketChannel接收到的TCP连接的请求
}catch(IOException e){
e.printStackTrace();
}
requestQueue = new LinkedBlockingQueue<SelectionKey>(500);
threadPool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++){
threadPool.submit(new Worker());
}
}
private static void listen(){
while (true) {
try {
selector.select();
Iterator<SelectionKey> keysIterator = selector.selectedKeys().iterator();
while (keysIterator.hasNext()) {
SelectionKey key = (SelectionKey) keysIterator.next();
//可以认为一个SelectionKey是代表了一个请求
keysIterator.remove();
handleRequest(key);
}
}catch (Throwable t) {
t.printStackTrace();
}
}
}
private static void handleRequest(SelectionKey key) throws IOException,ClosedChannelException{
//后台的线程池中的线程处理下面的代码逻辑
SocketChannel channel = null;
try {
//如果说这个Key是一个acceptable,也就是一个连接请求
if (key.isAcceptable()) {
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
//调用accept这个方法 就可以进行TCP三次握手了
channel = serverSocketChannel.accept();
//握手成功的话就可以获取到一个TCP连接好的SocketChannel
channel.configureBlocking(false);
channel.register(selector,SelectionKey.OP_READ);
//仅仅关注这个READ请求,就是人家发送数据过来的请求
}
//如果说这个key是readable,是个发送了数据过来的话,此时需要读取客户端发送过来的数据
else if (key.isReadable()) {
channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int count = channel.read(buffer);
//通过底层的socket读取数据,写buffer中,position可能就会变成21之类的
//你读取到了多少个字节,此时buffer的position就会变成多少
if (count > 0) {
//准备读取刚写入的数据,就是将limit设置为当前position,将position设置为0,丢弃mark。一般就是先写入数据,接着准备从0开始读这段数据,就可以用flip
//position = 0,limit = 21,仅仅读取buffer中,0~21这段刚刚写入进去的数据
buffer.flip();
System.out.println("服务端接收请求:"+new String(buffer.array(),0, count));
channel.register(selector,SelectionKey.OP_WRITE);
}
}else if (key.isWritable()){
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("收到".getBytes());
buffer.flip();
channel = (SocketChannel) key.channel();
channel.write(buffer);
channel.register(selector,SelectionKey.OP_READ);
}
}catch (Throwable t) {
t.printStackTrace();
if (channel != null) {
channel.close();
}
}
}
//创建一个线程任务来执行
static class Worker implements Runnable{
@Override
public void run(){
while (true){
try{
SelectionKey key = requestQueue.take();
handleRequest(key);
}catch(Exception e){
e.printStackTrace();
}
}
}
private void handleRequest(SelectionKey key) throws IOException,ClosedChannelException{
//假设想象一下,后台有个线程池获取到了请求
//下面的代码,都是在后台线程池的工作线程里在处理和执行
SocketChannel channel = null;
try {
//如果说这个key是个acceptable,是个连接请求的话
if (key.isAcceptable()) {
System.out.println("["+Thread.currentThread().getName()+"]接收到连接请求");
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
//调用accept方法 和客户端进行三次握手
channel = serverSocketChannel.accept();
System.out.println("["+Thread.currentThread().getName()+"]建立连接时获取到的channel="+ channel);
//如果三次握手成功了之后,就可以获取到一个建立好TCP连接的SocketChannel
//这个SocketChannel大概可以理解为,底层有一个Socket,是跟客户端进行连接的
//你的SocketChannel就是联通到那个Socket上去,负责进行网络数据的读写的
//设置为非阻塞的
channel.configureBlocking(false);
//关注的是Reade请求
channel.register(selector,SelectionKey.OP_READ);
}
//如果说这个key是readable,是个发送了数据过来的话,此时需要读取客户端发送过来的数据
else if (key.isReadable()) {
channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int count = channel.read(buffer);
//通过底层的socket读取数据,写入buffer中,position可能就会变成21之类的
//你读取到了多少个字节,此时buffer的position就会变成多少
System.out.println("["+Thread.currentThread().getName()+"]接收到请求");
if (count > 0) {
buffer.flip();
//position = 0,limit = 21,仅仅读取buffer中,0~21这段刚刚写入进去的数据
System.out.println("服务端接收请求:" + new String(buffer.array(),0, count));
channel.register(selector,SelectionKey.OP_WRITE);
}
}else if (key.isWritable()){
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("收到".getBytes());
buffer.flip();
channel = (SocketChannel) key.channel();
channel.write(buffer);
channel.register(selector,SelectionKey.OP_READ);
}
} catch (Throwable t) {
t.printStackTrace();
if (channel != null) {
channel.close();
}
}
}
}
}