常用的网络模型代码实例
1.1 BIO模型代码演示
1.1.1 服务端代码演示
//TCP协议代码
public class BIOServer {
private ServerSocket socket;//开发TCP的工具包
private final int port = 5676;
public BIOServer() {
try {
//将服务器绑定到特定端口上
socket = new ServerSocket(port);
} catch (IOException e) {
e.printStackTrace();
}
}
public void startTCPServer() {
//接收客户端的请求
try {
while (true) { //不停的接收客户端请求
Socket clientSocket = socket.accept(); //阻塞方法 阻塞到连接建立上为止
//TCP 建立连接 三次握手 三次握手的终点
// clientSocket请求连接的用户一一对应
//后面讲使用该clientSocket进行和这个用户之间的通信
new Thread(new ServerHandler(clientSocket)).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new BIOServer().startTCPServer();
}
}
public class ServerHandler implements Runnable {
private Socket clientSocket;
private BufferedWriter writer;
private BufferedReader reader;
private OutputStream outputStream;
private InputStream inputStream;
private Scanner scanner;
public ServerHandler(Socket clientSocket) {
scanner = new Scanner(System.in);
this.clientSocket = clientSocket;
try {
outputStream = clientSocket.getOutputStream();//负责发送消息
inputStream = clientSocket.getInputStream();// 负责接收消息
//字节转字符的过程
//文件传输
// BufferedOutputStream outputStream1 = new BufferedOutputStream(outputStream);
writer = new BufferedWriter(new OutputStreamWriter(outputStream));
reader = new BufferedReader(new InputStreamReader(inputStream));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
while (true) {
String str = reader.readLine();
System.out.println("接受到客户端的信息为 : " + str);
if (str.equals("exit")) {
break;
}
System.out.println("请输入回复信息:");
// String s = scanner.nextLine();
String s = "i receive you msg";
writer.write(s + "\n");
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
inputStream.close();
outputStream.close();
reader.close();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1.1.2 客户端代码演示
public class BIOClient {
private Socket socket;
private Scanner scanner;
private final int port = 5676;
private final String IP = "127.0.0.1";
private BufferedWriter writer;
private BufferedReader reader;
private OutputStream outputStream;
private InputStream inputStream;
private volatile boolean flag = true;
public BIOClient() {
scanner = new Scanner(System.in);
try {
socket = new Socket(IP, port); //请求和服务器建立连接
//TCP三次握手的起点 只要这个socket 建立成功说明连接建立成功
} catch (IOException e) {
e.printStackTrace();
}
}
public void startClient() {
try {
boolean closed = socket.isClosed();
if (!closed) {
outputStream = socket.getOutputStream();//负责发送消息
inputStream = socket.getInputStream();// 负责接收消息
writer = new BufferedWriter(new OutputStreamWriter(outputStream));
reader = new BufferedReader(new InputStreamReader(inputStream));
new Thread(new SendThread()).start();
while (flag) {
String str = reader.readLine();
System.out.println("接受到服务器的信息为 : " + str);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
inputStream.close();
outputStream.close();
reader.close();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class SendThread implements Runnable {
@Override
public void run() {
try {
while (true) {
System.out.println("请输入信息:");
String s = scanner.nextLine();
writer.write(s + "\n");
writer.flush();
if (s.equals("exit")) {
flag = false;
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new BIOClient().startClient();
}
}
1.2 NIO模型代码演示
1.2.1 服务端代码演示
1.2.1.1 单线程模式
public class NIOServerSingle {
private final int port = 8787;
private final int BLOCK_SIZE = 4096;//buff 大小
private Selector selector;
private ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK_SIZE);//发送数据
private ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK_SIZE);//发送数据
private static ExecutorService executor;
//构造函数
public NIOServerSingle() throws IOException {
//打开服务器套接字通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//服务器配置为非阻塞模式
serverSocketChannel.configureBlocking(false);
//获取与通道关联的 ServerSocket 对象
ServerSocket serverSocket = serverSocketChannel.socket();
//绑定端口
serverSocket.bind(new InetSocketAddress(port));
//打开一个选择器
selector = Selector.open();
//注册到 selector 上,等待连接
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("server:init successfuly.");
}
public static void main(String[] args) {
try {
NIOServerSingle nioServer = new NIOServerSingle();
nioServer.linstenr();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 监听端口
*/
private void linstenr() throws Exception {
while (true) {
//选择一组键
if (selector.select() > 0) {//int > 0
//返回获取选择的键集
Set<SelectionKey> selectionKeys = selector.selectedKeys();
if (selectionKeys.isEmpty()) {
continue;
}
//遍历,循环处理请求的键集
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
handlerKey(selectionKey);
iterator.remove();
}
Thread.sleep(100);
}
}
}
/**
* 处理对应的 SelectionKey
*
* @param selectionKey
*/
private void handlerKey(SelectionKey selectionKey) throws IOException {
ServerSocketChannel server;
SocketChannel client;
// 测试此键的通道是否已准备好接受新的套接字连接
if (selectionKey.isValid() && selectionKey.isAcceptable()) {
//此键对应的关联通道
server = (ServerSocketChannel) selectionKey.channel();
//接受到此通道套接字的连接
client = server.accept(); //注意这里accept到的 是channel类型的 和前面的socket类型不同
//配置为非阻塞
client.configureBlocking(false);
//注册到 selector 等待连接
client.register(selector, SelectionKey.OP_READ); //下面需要监听的是读事件
} else if (selectionKey.isValid() && selectionKey.isReadable()) {
client = (SocketChannel) selectionKey.channel();
//将缓冲区清空,下面读取
receiveBuffer.clear();
//将客户端发送来的数据读取到 buffer 中
int count = client.read(receiveBuffer);
if (count > 0) {
String receiveMessage = new String(receiveBuffer.array(), 0, count);
System.out.println("server:接受客户端的数据:" + receiveMessage);
client.register(selector, SelectionKey.OP_WRITE);
}
} else if (selectionKey.isValid() && selectionKey.isWritable()) {
//发送消息 buffer 清空
sendBuffer.clear();
//返回该键对应的通道
client = (SocketChannel) selectionKey.channel();
String sendMessage = "Send form server...Hello... " + new Random().nextInt(100) + " .";
//向缓冲区中写入数据
sendBuffer.put(sendMessage.getBytes());
//put 了数据,标志位被改变
sendBuffer.flip();
//数据输出到通道
client.write(sendBuffer);
System.out.println("server:服务器向客户端发送数据:" + sendMessage);
client.register(selector, SelectionKey.OP_READ);
}
}
}
1.2.1.2 多线程模式
public class NioServerThread {
private final int port = 8787;
private final int BLOCK_SIZE = 4096;//buff 大小
private Selector selector;
private ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK_SIZE);//发送数据
private ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK_SIZE);//发送数据
private static ExecutorService executor;
static {
executor = new ThreadPoolExecutor(5, 10, 10,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000));
}
//构造函数
public NioServerThread() throws IOException {
//打开服务器套接字通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//服务器配置为非阻塞模式
serverSocketChannel.configureBlocking(false);
//获取与通道关联的 ServerSocket 对象
ServerSocket serverSocket = serverSocketChannel.socket();
//绑定端口
serverSocket.bind(new InetSocketAddress(port));
//打开一个选择器
selector = Selector.open();
//注册到 selector 上,等待连接
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("server:init successfuly.");
}
public static void main(String[] args) {
try {
NioServerThread nioServer = new NioServerThread();
nioServer.linstenr();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 监听端口
*/
private void linstenr() throws Exception {
while (true) {
//选择一组键
if (selector.select() > 0) {//int > 0
//返回获取选择的键集
Set<SelectionKey> selectionKeys = selector.selectedKeys();
if (selectionKeys.isEmpty()) {
continue;
}
//遍历,循环处理请求的键集
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
handlerKey(selectionKey);
iterator.remove();
}
Thread.sleep(100);
}
}
}
/**
* 处理对应的 SelectionKey
*
* @param selectionKey
*/
private void handlerKey(SelectionKey selectionKey) throws IOException {
ServerSocketChannel server;
SocketChannel client;
// 测试此键的通道是否已准备好接受新的套接字连接
if (selectionKey.isValid() && selectionKey.isAcceptable()) {
//此键对应的关联通道
server = (ServerSocketChannel) selectionKey.channel();
//接受到此通道套接字的连接
client = server.accept(); //注意这里accept到的 是channel类型的 和前面的socket类型不同
//配置为非阻塞
client.configureBlocking(false);
//注册到 selector 等待连接
client.register(selector, SelectionKey.OP_READ); //下面需要监听的是读事件
} else if (selectionKey.isValid() && selectionKey.isReadable()) {
executor.submit(new TimeServerTask(selectionKey));
}
}
}
- 子线程:
public class TimeServerTask implements Runnable {
private SelectionKey selectionKey;
SocketChannel client;
private ByteBuffer receiveBuffer = ByteBuffer.allocate(4096);//接收数据
private ByteBuffer sendBuffer = ByteBuffer.allocate(4096);//发送数据
public TimeServerTask(SelectionKey selectionKey) {
this.selectionKey = selectionKey;
}
@Override
public void run() {
// SocketChannel channel = (SocketChannel) selectionKey.channel();
// ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
client = (SocketChannel) selectionKey.channel();
//将缓冲区清空,下面读取
receiveBuffer.clear();
//将客户端发送来的数据读取到 buffer 中
int count = 0;
try {
count = client.read(receiveBuffer);
if (count > 0) {
String receiveMessage = new String(receiveBuffer.array(), 0, count);
System.out.println("server:接受客户端的数据:" + receiveMessage);
// client.register(selector, SelectionKey.OP_WRITE);
sendBuffer.clear();
//返回该键对应的通道
client = (SocketChannel) selectionKey.channel();
String sendMessage = "Send form server...Hello... " + new Random().nextInt(1
+ " .";
//向缓冲区中写入数据
sendBuffer.put(sendMessage.getBytes());
//put 了数据,标志位被改变
sendBuffer.flip();
//数据输出到通道
client.write(sendBuffer);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.2.1.3 主从 Reactor 模式
public class NioServer {
private final int port = 8787;
private final int BLOCK_SIZE = 4096;//buff 大小
private Selector selector;
private ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK_SIZE);//发送数据
//构造函数
public NioServer() throws IOException {
//打开服务器套接字通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//服务器配置为非阻塞模式
serverSocketChannel.configureBlocking(false);
//获取与通道关联的 ServerSocket 对象
ServerSocket serverSocket = serverSocketChannel.socket();
//绑定端口
serverSocket.bind(new InetSocketAddress(port));
//打开一个选择器
selector = Selector.open();
//注册到 selector 上,等待连接
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("server:init successfuly.");
}
public static void main(String[] args) {
try {
NioServer nioServer = new NioServer();
nioServer.linstenr();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 监听端口
*/
private void linstenr() throws Exception {
while (true) {
//选择一组键
if (selector.select() > 0) {//int > 0
//返回获取选择的键集
Set<SelectionKey> selectionKeys = selector.selectedKeys();
if (selectionKeys.isEmpty()) {
continue;
}
//遍历,循环处理请求的键集
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
handlerKey(selectionKey);
iterator.remove();
}
Thread.sleep(100);
}
}
}
/**
* 处理对应的 SelectionKey
*
* @param selectionKey
*/
private void handlerKey(SelectionKey selectionKey) throws IOException {
ServerSocketChannel server;
SocketChannel client;
// 测试此键的通道是否已准备好接受新的套接字连接
if (selectionKey.isValid() && selectionKey.isAcceptable()) {
//此键对应的关联通道
server = (ServerSocketChannel) selectionKey.channel();
//接受到此通道套接字的连接
client = server.accept(); //注意这里accept到的 是channel类型的 和前面的socket类型不同
//配置为非阻塞
client.configureBlocking(false);
SerHandler runnable = new SerHandler();
Selector serHandlerSelector = runnable.getSelector();
client.register(serHandlerSelector, SelectionKey.OP_READ);
new Thread(runnable).start();
}
}
}
public class SerHandler implements Runnable {
Selector selector;
SocketChannel client;
private ByteBuffer receiveBuffer = ByteBuffer.allocate(4096);//接收数据
private ByteBuffer sendBuffer = ByteBuffer.allocate(4096);//发送数据
public SerHandler() {
try {
this.selector = Selector.open();
} catch (IOException e) {
e.printStackTrace();
}
}
public Selector getSelector() {
return selector;
}
public void setSelector(Selector selector) {
this.selector = selector;
}
@Override
public void run() {
try {
while (true) {
if (selector.select() > 0) {
Set<SelectionKey> selectionKeys = selector.selectedKeys();
if (selectionKeys.isEmpty()) {
continue;
}
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
handlerKey(selectionKey);
iterator.remove();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void handlerKey(SelectionKey selectionKey) throws IOException {
if (selectionKey.isValid() && selectionKey.isReadable()) {
client = (SocketChannel) selectionKey.channel();
//将缓冲区清空,下面读取
receiveBuffer.clear();
//将客户端发送来的数据读取到 buffer 中
int count = client.read(receiveBuffer);
if (count > 0) {
String receiveMessage = new String(receiveBuffer.array(), 0, count);
System.out.println("server:接受客户端的数据:" + receiveMessage);
sendBuffer.clear();
//返回该键对应的通道
client = (SocketChannel) selectionKey.channel();
String sendMessage = "Send form server...Hello... " + new Random().nextInt(100) + " .";
//向缓冲区中写入数据
sendBuffer.put(sendMessage.getBytes());
//put 了数据,标志位被改变
sendBuffer.flip();
//数据输出到通道
client.write(sendBuffer);
}
}
}
}
1.2.2 客户端代码演示
public class NioClient {
private static final int BLOCK_SIZE = 4096;//4k
private static final InetSocketAddress SERVER_ADDRESS =
new InetSocketAddress("127.0.0.1", 8787);
private static ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK_SIZE);
private static ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK_SIZE);
public static void main(String[] args) {
try {
//打开 socket 通道
SocketChannel socketChannel = SocketChannel.open();
//设置为非阻塞模式
socketChannel.configureBlocking(false);
//打开选择器
Selector selector = Selector.open();
//向 selector 选择器注册此通道
socketChannel.register(selector, SelectionKey.OP_CONNECT);
//链接
socketChannel.connect(SERVER_ADDRESS);
SocketChannel client;
while (true) {
//选择一组键
if (selector.select() > 0) {
//返回此选择器的已选择键集
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
//遍历对应的 SelectionKey 处理
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
//判断此键的通道是否已完成其套接字连接操作
if (selectionKey.isValid() && selectionKey.isConnectable()) { //是否已经连接上
System.out.println("Client: already connected.");
client = (SocketChannel) selectionKey.channel();
//判断该通道是否进行连接过程、完成连接过程
if (client.isConnectionPending()) {
client.finishConnect();
sendBuffer.clear();
sendBuffer.put("hello nio server".getBytes());
sendBuffer.flip();
client.write(sendBuffer); //将数据写入该通道
client.register(selector, SelectionKey.OP_READ);
}
} else if (selectionKey.isReadable()) {
//获取该键中对应的通道
client = (SocketChannel) selectionKey.channel();
receiveBuffer.clear();
int count = client.read(receiveBuffer);
if (count > 0) {
String receiveMessage = new String(receiveBuffer.array(), 0, count);
System.out.println("Client:接收到来自 Server 的消息," + receiveMessage);
sendBuffer.clear();
String sendText = "hello server,key..";
sendBuffer.put(sendText.getBytes());
sendBuffer.flip();
client.write(sendBuffer);
}
}
}
selectionKeys.clear();
Thread.sleep(100);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
1.3 AIO模型代码演示
在实现 AIO 模型时我们需要实现 CompletionHandler 接口,实现相应的 completed 和 failed 方法。然后通过 AIOchannel 在合适的场景下调用合适的我们自己实现的 CompletionHandler 的子接口。如下图所示,我们在连接事件发生时调用 accept 方法调用处理连接的 handler 当读事件发生时调用处理读事件的 Handler 当写事件发生时调用处理写事件的 Handler。注意我们的方法都是异步调用所以事件的处理何时开始何时结束取决于事件本身。
1.3.1 服务端代码演示
服务器这里至少要实现 3 种 Handler 分别负责读、写、连接事件。并且必须要都继承 CompletionHandler 接口。
public class ServerAio {
private static int DEFAULT_PORT = 8787;
private static AsyncServerHandler serverHandle;
public volatile static long clientCount = 0;
public static void start() {
start(DEFAULT_PORT);
}
public static synchronized void start(int port) {
if (serverHandle != null)
return;
serverHandle = new AsyncServerHandler(port);
serverHandle.run();
// new Thread(serverHandle, "server").start();
}
public static void main(String[] args) {
ServerAio.start();
}
}
public class AsyncServerHandler {
public CountDownLatch latch;
// public AsynchronousServerSocketChannel channel;
ExecutorService executor = Executors.newFixedThreadPool(20);
//以指定线程池来创建一个 AsynchronousChannelGroup
//AsynchronousChannelGroup 是异步 channel 的分组管理器
AsynchronousChannelGroup channelGroup;
//以指定线程池来创建一个 AsynchronousServerSocketChannel
AsynchronousServerSocketChannel serverChannel;
{
try {
channelGroup = AsynchronousChannelGroup
.withThreadPool(executor);
serverChannel
= AsynchronousServerSocketChannel.open(channelGroup);
} catch (IOException e) {
e.printStackTrace();
}
}
public AsyncServerHandler(int port) {
try {
//创建服务端通道
serverChannel = AsynchronousServerSocketChannel.open();
//绑定端口
serverChannel.bind(new InetSocketAddress(port));
System.out.println("****** aio server success ****");
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
latch = new CountDownLatch(1);
//用于接收客户端的连接
serverChannel.accept(this, new AcceptHandler());//回调的方法
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, AsyncServerHandler> {
@Override
public void completed(AsynchronousSocketChannel channel, AsyncServerHandler serverHandler) {
//继续接受其他客户端的请求
ServerAio.clientCount++;
System.out.println("连接的客户端数:" + ServerAio.clientCount);
serverHandler.serverChannel.accept(serverHandler, this);//回调方法 this: 需要不停 accept 客户端
//创建新的 Buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);
//建立连接之后当然要先看是否有客户端有什请求
//异步读操作,参数的定义:第一个参数:接收缓冲区,用于异步从 channel 读取数据包;
//第二个参数:异步 channel 携带的附件,通知回调的时候作为入参参数,这里是作为 ReadCompletionHandler 的入参
//通知回调的业务handler,也就是数据从channel读到ByteBuffer完成后的回调handler,这里是 ReadCompletionHandler
channel.read(buffer, buffer, new ReadHandler(channel));
}
@Override
public void failed(Throwable exc, AsyncServerHandler serverHandler) {
exc.printStackTrace();
serverHandler.latch.countDown();
}
}
public class ReadHandler implements CompletionHandler<Integer, ByteBuffer> {
//用于读取半包消息和发送应答
private AsynchronousSocketChannel channel;
public ReadHandler(AsynchronousSocketChannel channel) {
this.channel = channel;
}
//读取到消息后的处理
@Override
public void completed(Integer result, ByteBuffer attachment) {
System.out.println(result);
//flip 操作
attachment.flip();
//根据
byte[] message = new byte[attachment.remaining()];
attachment.get(message);
String expression = new String(message);
System.out.println("服务器收到消息: " + expression);
String calrResult = null;
try {
calrResult = String.valueOf(expression.hashCode());
} catch (Exception e) {
calrResult = "计算错误:" + e.getMessage();
}
//向客户端发送消息
doWrite(calrResult);
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
try {
this.channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//发送消息
private void doWrite(String result) {
byte[] bytes = result.getBytes();
ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
writeBuffer.put(bytes);
writeBuffer.flip();
//异步写数据 参数与前面的 read 一样
channel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer buffer) {
//如果没有发送完,就继续发送直到完成
if (buffer.hasRemaining())
channel.write(buffer, buffer, this);
else {
//创建新的 Buffer
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
//异步读 第三个参数为接收消息回调的业务 Handler
channel.read(readBuffer, readBuffer, new ReadHandler(channel));
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
exc.printStackTrace();
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
1.3.2 客户端代码演示
public class ClientAio {
private static String DEFAULT_HOST = "127.0.0.1";
private static int DEFAULT_PORT = 8787;
private static AsyncClientHandler clientHandle;
public static void start() {
start(DEFAULT_HOST, DEFAULT_PORT);
}
public static synchronized void start(String ip, int port) {
if (clientHandle != null)
return;
clientHandle = new AsyncClientHandler(ip, port);
new Thread(clientHandle, "Client").start();
}
//向服务器发送消息
public static boolean sendMsg(String msg) {
clientHandle.sendMsg(msg);
return true;
}
public static void main(String[] args) {
ClientAio.start();
System.out.println("请输入请求消息:");
Scanner scanner = new Scanner(System.in);
while (ClientAio.sendMsg(scanner.nextLine())) ;
}
}
public class AsyncClientHandler implements CompletionHandler<Void, AsyncClientHandler>, Runnable {
ExecutorService executor = Executors.newFixedThreadPool(20);
//以指定线程池来创建一个 AsynchronousChannelGroup
//AsynchronousChannelGroup 是异步 channel 的分组管理器
AsynchronousChannelGroup channelGroup;
//以指定线程池来创建一个 AsynchronousSocketChannel
AsynchronousSocketChannel clientChannel;
private String host;
private int port;
private CountDownLatch latch;
public AsyncClientHandler(String host, int port) {
this.host = host;
this.port = port;
//创建异步的客户端通道
try {
channelGroup = AsynchronousChannelGroup
.withThreadPool(executor);
clientChannel
= AsynchronousSocketChannel.open(channelGroup);
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
//创建 CountDownLatch 等待
latch = new CountDownLatch(1);
//发起异步连接操作,回调参数就是这个类本身,如果连接成功会回调 completed 方法
System.out.println("开始建立连接");
clientChannel.connect(new InetSocketAddress(host, port), this, this);
try {
latch.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
clientChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//连接服务器成功
//意味着 TCP 三次握手完成
@Override
public void completed(Void result, AsyncClientHandler attachment) {
System.out.println("客户端成功连接到服务器...");
}
//连接服务器失败 会调用这个方法
@Override
public void failed(Throwable exc, AsyncClientHandler attachment) {
System.err.println("连接服务器失败...");
exc.printStackTrace();
try {
clientChannel.close();
latch.countDown();
} catch (IOException e) {
e.printStackTrace();
}
}
//向服务器发送消息
public void sendMsg(String msg) {
byte[] req = msg.getBytes();
ByteBuffer writeBuffer = ByteBuffer.allocate(req.length);
writeBuffer.put(req);
writeBuffer.flip();
//异步写
clientChannel.write(writeBuffer, writeBuffer, new WriteHandler(clientChannel, latch));
}
}
public class WriteHandler implements CompletionHandler<Integer, ByteBuffer> {
private AsynchronousSocketChannel clientChannel;
private CountDownLatch latch;
public WriteHandler(AsynchronousSocketChannel clientChannel, CountDownLatch latch) {
this.clientChannel = clientChannel;
this.latch = latch;
}
@Override
public void completed(Integer result, ByteBuffer buffer) {
//完成全部数据的写入
if (buffer.hasRemaining()) {
clientChannel.write(buffer, buffer, this);
} else {
//读取数据
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
clientChannel.read(readBuffer, readBuffer, new ReadHandler(clientChannel, latch));
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.err.println("数据发送失败...");
try {
clientChannel.close();
latch.countDown();
} catch (IOException e) {
}
}
}
public class ReadHandler implements CompletionHandler<Integer, ByteBuffer> {
private AsynchronousSocketChannel clientChannel;
private CountDownLatch latch;
public ReadHandler(AsynchronousSocketChannel clientChannel, CountDownLatch latch) {
this.clientChannel = clientChannel;
this.latch = latch;
}
@Override
public void completed(Integer result, ByteBuffer buffer) {
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String body;
body = new String(bytes);
System.out.println("客户端收到结果:" + body);
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.err.println("数据读取失败...");
try {
clientChannel.close();
latch.countDown();
} catch (IOException e) {
}
}
}