Java网络编程-Socket编程初涉五(AIO模型的简易客户端-服务器)
发布日期:2021-06-30 16:02:26
浏览次数:2
分类:技术文章
本文共 6989 字,大约阅读时间需要 23 分钟。
推荐:
Java网络编程-Socket编程初涉五(AIO模型的简易客户端-服务器)
什么是AIO模型?
功能
这里实现一个很简单的客户端-服务器,客户端连接服务器后,发送消息给服务器,服务器直接返回该消息给客户端即可,这只是个尝鲜版,以后也会用AIO模型来实现多人聊天室。
服务器
服务器的主要逻辑如下:
- 打开管道
AsynchronousServerSocketChannel
,绑定、监听端口(启动服务器)。 - 服务器异步调用
accept
(通过CompletionHandler
的实现类AcceptHandler
来实现异步调用,因为有回调机制),使用System.in.read()
来减少while
循环中频繁异步调用accept
。 - 当有客户端连接成功后,触发回调函数
completed
(AcceptHandler
类),然后再异步调用一次accept
,等待下一个客户端连接成功时触发(先存着);回调函数completed
会把AsynchronousSocketChannel
传过来,调用AsynchronousSocketChannel
的read
方法,来读取客户端发送过来的消息。 - 将
AsynchronousSocketChannel
的read
和write
方法实现异步调用(通过CompletionHandler
的实现类ClientHandler
来实现异步调用,因为有回调机制),为了分清楚是read
还是write
,attachment
传一个Map
(Map里面记录必要数据buffer
、type
)。当读取客户端发送的消息后,再将该消息发送给客户端(都是通过AsynchronousSocketChannel
,所以将它定义为ClientHandler
类的属性),即异步调用read
,触发回调函数(read
的回调函数),在回调函数里面再异步调用write
,触发回调函数(write
的回调函数),在回调函数里面再异步调用read
。
可能会看起来懵懵懂懂,可以结合代码来理解,代码有一定的注释。
服务器完整代码:
package aio.test;import java.io.Closeable;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.AsynchronousServerSocketChannel;import java.nio.channels.AsynchronousSocketChannel;import java.nio.channels.CompletionHandler;import java.util.HashMap;import java.util.Map;public class Server { final String LOCALHOST = "localhost"; final int DEFAULT_PORT = 8888; AsynchronousServerSocketChannel serverChannel; private void close(Closeable closeable){ if(closeable != null){ try { closeable.close(); } catch (IOException e) { e.printStackTrace(); } } } public void start(){ try { // 打开通道 serverChannel = AsynchronousServerSocketChannel.open(); // 绑定、监听端口 serverChannel.bind(new InetSocketAddress(DEFAULT_PORT)); System.out.println("启动服务器,监听端口:"+DEFAULT_PORT+"..."); while(true){ // 异步调用 serverChannel.accept(null,new AcceptHandler()); // 不会频繁调用accept的小技巧 System.in.read(); } } catch (IOException e) { e.printStackTrace(); } finally{ close(serverChannel); } } private class AcceptHandler implements CompletionHandler{ @Override public void completed(AsynchronousSocketChannel result, Object attachment) { //此次调用accept完成,再一次调用accept,等待下一个客户端连接 if(serverChannel.isOpen()) { serverChannel.accept(null , this); } AsynchronousSocketChannel clientChannel = result; if(clientChannel != null && clientChannel.isOpen()){ ClientHandler handler = new ClientHandler(clientChannel); ByteBuffer buffer = ByteBuffer.allocate(1024); Map info = new HashMap<>(); info.put("type", "read"); info.put("buffer" , buffer); clientChannel.read(buffer , info, handler); } } @Override public void failed(Throwable exc, Object attachment) { // 处理错误 } } private class ClientHandler implements CompletionHandler { private AsynchronousSocketChannel clientChannel; public ClientHandler(AsynchronousSocketChannel channel){ this.clientChannel = channel; } @Override public void completed(Integer result, Object attachment) { Map info = (Map ) attachment; String type = (String) info.get("type"); if(type.equals("read")){ ByteBuffer buffer = (ByteBuffer) info.get("buffer"); // 读模式 buffer.flip(); info.put("type" , "write"); clientChannel.write(buffer ,info , this); // 写模式(也相当于清空) buffer.clear(); } else if(type.equals("write")){ ByteBuffer buffer = ByteBuffer.allocate(1024); info.put("type" , "read"); info.put("buffer" , buffer); clientChannel.read(buffer , info , this); } } @Override public void failed(Throwable exc, Object attachment) { // 处理错误 } } public static void main(String[] args) { Server server = new Server(); server.start(); }}
客户端
为了让大家了解其他实现异步调用的方法,客户端使用Future
来实现异步调用(正如该单词的英文意思将来
、未来
)。
Future
实现简单的异步调用,会简单一点。
Future
实例,再调用该实例的get
方法会阻塞,等待该方法调用完成,阻塞便解除(具体看代码吧,客户端比较简单,注释还是比较全的)。 package aio.test;import java.io.BufferedReader;import java.io.Closeable;import java.io.IOException;import java.io.InputStreamReader;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.AsynchronousSocketChannel;import java.util.concurrent.ExecutionException;import java.util.concurrent.Future;public class Client { final String LOCALHOST = "localhost"; final int DEFAULT_PORT = 8888; AsynchronousSocketChannel clientChannel; private void close(Closeable closeable){ if(closeable != null){ try { closeable.close(); } catch (IOException e) { e.printStackTrace(); } } } public void start(){ try { // 创建Channel clientChannel = AsynchronousSocketChannel.open(); Futurefuture = clientChannel.connect( new InetSocketAddress(LOCALHOST , DEFAULT_PORT)); // 当未连接成功前,这里是阻塞的 future.get(); // 等待用户的输入 BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in)); while(true){ String input = consoleReader.readLine(); byte[] inputBytes = input.getBytes(); // 得到buffer的模式是读模式,可以Debug看一看 ByteBuffer buffer = ByteBuffer.wrap(inputBytes); Future writeResult = clientChannel.write(buffer); // 等待成功写入用户管道 writeResult.get(); // 写模式 buffer.clear(); Future readResult = clientChannel.read(buffer); // 等待成功读取用户管道 readResult.get(); String echo = new String(buffer.array()); System.out.println(echo); } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } finally { close(clientChannel); } } public static void main(String[] args) { Client client = new Client(); client.start(); }}
测试
测试没什么问题。
这里便完成了AIO模型的简易客户端-服务器,大家可以动手试一试,使用两种实现异步调用的方法。
如果有说错的地方,请大家不吝赐教(记得留言哦~~~~)。
转载地址:https://kaven.blog.csdn.net/article/details/104184117 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
逛到本站,mark一下
[***.202.152.39]2024年04月13日 22时42分56秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
委员会怎么验证比特币真伪
2019-05-01
迅雷陷入窘迫,但是无可替代
2019-05-01
PHP之 使用PHPMailer插件实现邮件发送功能
2019-05-01
Linux之 关于VM虚拟机网卡的设置
2019-05-01
Lnmp环境搭建之php-7.2.19安装配置
2019-05-01
《增长黑客》(肖恩·艾利斯)学习笔记——第一部分 方法
2019-05-01
《增长黑客》(肖恩·艾利斯)学习笔记——第二部分 实战
2019-05-01
冒泡排序及优化(JAVA算法)
2019-05-01
九九乘法表(Java,JavaScript)
2019-05-01
Mysql学习笔记(9):数据类型和约束
2019-05-01
Mysql学习笔记(10):事务、视图
2019-05-01
JDBC学习笔记(1):JDBC概述
2019-05-01
JAVA进阶学习笔记(8):反射
2019-05-01
JDBC学习笔记(2):获取数据库连接
2019-05-01
作用域 & 作用域链(ES6学习笔记)
2019-05-01