一、bio写的时间服务器
1、一个请求对应一个线程版本
server端代码
package com.spring.test.service.netty.server.bio;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author <a href="">尚晓飞</a>
* @date 7:47 PM 2019/7/19
*/
public class BIOTimerServer {
public static void main(String[] args) {
//启动服务端
BIOTimerServer server=new BIOTimerServer();
server.startServer();
}
private int port = 8080;
private ServerSocket serverSocket;
public void startServer() {
try {
System.out.println("=====服务初始化开始=====");
serverSocket = new ServerSocket(port);
System.out.println("=====服务初始化完毕=====");
while (true) {
Socket socket = serverSocket.accept();
System.out.println("=====服务端接收一个请求=====");
new SocketHandlerThread(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (this.serverSocket != null) {
try {
this.serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* socket处理线程
*/
class SocketHandlerThread extends Thread {
private Socket socket;
SocketHandlerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
System.out.println("======请求处理开始========");
BufferedReader in = null;
PrintWriter out = null;
try {
//step1:初始化输入流(读请求)
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//step2:初始化输出流(写响应)
out = new PrintWriter(this.socket.getOutputStream(),true);
//step3:读取请求内容
StringBuilder req = new StringBuilder();
String temp;
while (true){
temp= in.readLine();
if(StringUtils.isNotBlank(temp)){
req.append(temp);
break;
}
}
//step4:处理请求
System.out.println("请求内容为=>" + req.toString());
String response = DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss");
System.out.println("响应内容为=>" + response);
//step5:响应请求
out.println(response);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
out.close();
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("======请求处理结束========");
}
}
View Code
client端代码
package com.spring.test.service.netty.server.bio;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
* @author <a href="">尚晓飞</a>
* @date 6:19 PM 2019/7/21
*/
public class BIOTimerClient {
public static void main(String[] args) {
//客户端发送请求
BIOTimerClient bioTimerClient=new BIOTimerClient(8080,"127.0.0.1");
String resp=bioTimerClient.req("query Current Time");
System.out.println("响应内容为=>"+resp);
}
private int port;
private String localhost;
public BIOTimerClient(int port, String address) {
this.port = port;
this.localhost = address;
}
public String req(String req) {
Socket socket = null;
BufferedReader in = null;
PrintWriter out = null;
StringBuilder response;
try {
socket = new Socket(this.localhost, this.port);
//发送请求的输出流
out = new PrintWriter(socket.getOutputStream(),true);
//接收响应的输入流
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//发送请求
System.out.println("==开始发送请求==>" + req);
out.println(req);
//读取响应
response = new StringBuilder();
String temp;
while (StringUtils.isNotBlank(temp = in.readLine())) {
response.append(temp);
}
System.out.println("==客户端接收响应成功==");
return response.toString();
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out!=null){
out.close();
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
View Code
1、服务端使用线程池版本
server端代码
package com.spring.test.service.netty.server.bio;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* @author <a href="">尚晓飞</a>
* @date 7:47 PM 2019/7/19
*/
public class BIOTimerServer {
public static void main(String[] args) {
//启动服务端
BIOTimerServer server = new BIOTimerServer();
server.startServer();
}
private int port = 8080;
private ServerSocket serverSocket;
/**
* 初始化一个工作线程池,用来处理客户端的请求
* 优点:相对于第一版的一个请求一个工作线程,不会出现客户单大量请求,导致服务端开启大量线程,把服务端资源耗尽的问题。
* 缺点:固定的线程池大小,代表服务端有一定的处理极限(并发数就是线程池的最大数),一但出现服务端或客户端的I/O因为网络原因出现阻塞
* 则服务端线程资源就会被长时间占用,线程池占满,服务端无法处理新的请求,客户端就会出现超时或访问被拒绝的情况
*/
private Executor executor= Executors.newFixedThreadPool(20);
public void startServer() {
try {
System.out.println("=====服务初始化开始=====");
serverSocket = new ServerSocket(port);
System.out.println("=====服务初始化完毕=====");
while (true) {
Socket socket = serverSocket.accept();
System.out.println("=====服务端接收一个请求=====");
//模拟一个工作线程池,用来处理客户端请求
executor.execute(new SocketHandlerThread(socket));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (this.serverSocket != null) {
try {
this.serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* socket处理线程
*/
class SocketHandlerThread extends Thread {
private Socket socket;
SocketHandlerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
System.out.println("======请求处理开始========");
BufferedReader in = null;
PrintWriter out = null;
try {
//step1:初始化输入流(读请求)
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//step2:初始化输出流(写响应)
out = new PrintWriter(this.socket.getOutputStream(), true);
//step3:读取请求内容
StringBuilder req = new StringBuilder();
String temp;
while (true) {
temp = in.readLine();
if (StringUtils.isNotBlank(temp)) {
req.append(temp);
break;
}
}
//step4:处理请求
System.out.println("请求内容为=>" + req.toString());
String response = DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss");
System.out.println("响应内容为=>" + response);
//step5:响应请求
out.println(response);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
out.close();
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("======请求处理结束========");
}
}
View Code
client端代码
package com.spring.test.service.netty.server.bio;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
* @author <a href="">尚晓飞</a>
* @date 6:19 PM 2019/7/21
*/
public class BIOTimerClient {
public static void main(String[] args) {
//客户端发送请求
BIOTimerClient bioTimerClient=new BIOTimerClient(8080,"127.0.0.1");
String resp=bioTimerClient.req("query Current Time");
System.out.println("响应内容为=>"+resp);
}
private int port;
private String localhost;
public BIOTimerClient(int port, String address) {
this.port = port;
this.localhost = address;
}
public String req(String req) {
Socket socket = null;
BufferedReader in = null;
PrintWriter out = null;
StringBuilder response;
try {
socket = new Socket(this.localhost, this.port);
//发送请求的输出流
out = new PrintWriter(socket.getOutputStream(),true);
//接收响应的输入流
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//发送请求
System.out.println("==开始发送请求==>" + req);
out.println(req);
//读取响应
response = new StringBuilder();
String temp;
while (StringUtils.isNotBlank(temp = in.readLine())) {
response.append(temp);
}
System.out.println("==客户端接收响应成功==");
return response.toString();
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out!=null){
out.close();
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
View Code
二、nio写的时间服务器
server端代码
package com.spring.test.service.netty.server.nio;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
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.Iterator;
import java.util.Set;
/**
* @author <a href="">尚晓飞</a>
* @date 7:24 PM 2019/7/21
*/
public class NIOTimerServer extends Thread {
public static void main(String[] args) {
//启动服务端
NIOTimerServer server=new NIOTimerServer(8080);
server.start();
}
private int port;
/**
* 多路复用器
*/
private Selector selector;
/**
* 服务端通信的管道
*/
private ServerSocketChannel serverSocketChannel;
/**
* 服务端是否停止
*/
private volatile boolean isStop;
public NIOTimerServer(int port) {
try {
System.out.println("========初始化服务端开始=========");
this.port=port;
//新建多路复用器
selector = Selector.open();
//新建服务端管道,用于监听客户端连接
serverSocketChannel = ServerSocketChannel.open();
//将I/O设置为非阻塞模式
serverSocketChannel.configureBlocking(false);
//绑定端口号
serverSocketChannel.socket().bind(new InetSocketAddress(this.port), 1024);
//将serverSocketChannel注册到多路复用器上,用于监听客户端接入的OP_ACCEPT事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("========初始化服务端结束==========");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (!isStop) {
//通过多路复用器,监听网络事件
try {
//如果没有网络事件,则阻塞(1秒钟退出阻塞),若存在网络事件,则直接向下一句代码执行。
selector.select(1000);
//获取已准备就绪的网络事件
Set<SelectionKey> selectionKeys = selector.selectedKeys();
//遍历已经就绪的网络事件,并进行处理
Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
SelectionKey selectionKey;
while (selectionKeyIterator.hasNext()) {
selectionKey = selectionKeyIterator.next();
selectionKeyIterator.remove();
handlerKey(selectionKey);
}
} catch (IOException e) {
e.printStackTrace();
}
}
if(selector!=null){
try {
selector.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void handlerKey(SelectionKey selectionKey) throws IOException {
//判断selectionKey是否是有效的
if (selectionKey.isValid()) {
if (selectionKey.isAcceptable()) {
//客户端新接入
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
//注册监听读取请求的网络事件
socketChannel.register(selector, SelectionKey.OP_READ);
}
if (selectionKey.isReadable()) {
//当前网络事件,是读取客户端的请求内容
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int readBytes = socketChannel.read(byteBuffer);
if (readBytes > 0) {
//读取的客户端请求内容
byteBuffer.flip();
byte[] bytes=new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
String requestBoy=new String(bytes,"utf-8");
System.out.println("客户端请求内容=>"+requestBoy);
//处理请求
String response = DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss");
//响应请求
doResponse(socketChannel,response);
}else if(readBytes<0){
//客户端链路关闭
selectionKey.cancel();
socketChannel.close();
}else {
//读到0字节忽略
}
}
}
}
private void doResponse(SocketChannel socketChannel,String response) throws IOException {
if(StringUtils.isNotBlank(response)){
byte[] resp=response.getBytes();
ByteBuffer byteBuffer=ByteBuffer.allocate(resp.length);
byteBuffer.put(resp);
byteBuffer.flip();
socketChannel.write(byteBuffer);
}
}
}
View Code
client端代码
package com.spring.test.service.netty.server.nio;
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;
import java.util.Set;
/**
* @author <a href="">尚晓飞</a>
* @date 8:48 PM 2019/7/21
*/
public class NIOTimerClient extends Thread{
public static void main(String[] args) {
NIOTimerClient nioTimerClient=new NIOTimerClient("127.0.0.1",8080);
nioTimerClient.start();
}
private String address;
private int port;
private Selector selector;
private SocketChannel socketChannel;
private volatile boolean isStop;
NIOTimerClient(String address,int port){
this.address=address;
this.port=port;
try {
selector= Selector.open();
socketChannel=SocketChannel.open();
socketChannel.configureBlocking(false);
}catch (Exception e){
}
}
@Override
public void run() {
try {
//向服务端发送请求
doConnection();
}catch (Exception e){
e.printStackTrace();
}
while (!isStop){
try {
selector.select(1000);
Set<SelectionKey> selectionKeys= selector.selectedKeys();
Iterator<SelectionKey> selectionKeyIterator= selectionKeys.iterator();
SelectionKey selectionKey=null;
while (selectionKeyIterator.hasNext()){
selectionKey=selectionKeyIterator.next();
selectionKeyIterator.remove();
try {
handler(selectionKey);
}catch (Exception e){
if(selectionKey!=null){
selectionKey.cancel();
if(selectionKey.channel()!=null){
selectionKey.channel().close();
}
}
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
}
}
if(selector!=null){
try {
selector.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 向服务端发起连接
* @throws IOException
*/
private void doConnection() throws IOException {
if(socketChannel.connect(new InetSocketAddress(address,port))){
//连接成功
socketChannel.register(selector, SelectionKey.OP_READ);
doRequest(socketChannel);
}else {
socketChannel.register(selector,SelectionKey.OP_CONNECT);
}
}
/**
* 向服务端发起请求
*/
private void doRequest(SocketChannel socketChannel) throws IOException {
byte[] request="query current time!".getBytes();
ByteBuffer byteBuffer=ByteBuffer.allocate(request.length);
byteBuffer.put(request);
byteBuffer.flip();
socketChannel.write(byteBuffer);
if(!byteBuffer.hasRemaining()){
System.out.println("向服务端请求发送成功");
}
}
private void handler(SelectionKey selectionKey) throws IOException {
if(selectionKey.isValid()){
SocketChannel socketChannel= (SocketChannel) selectionKey.channel();
//当前是网络连接完成事件
if(selectionKey.isConnectable()){
if(socketChannel.finishConnect()){
socketChannel.register(selector,SelectionKey.OP_READ);
doRequest(socketChannel);
}else {
//连接失败
System.out.println("连接失败");
}
}
//当前是网络读取响应事件
if(selectionKey.isReadable()){
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
int readResp=socketChannel.read(byteBuffer);
if(readResp>0){
byteBuffer.flip();
byte[] bytes=new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
String resp=new String(bytes,"utf-8");
System.out.println("服务端响应为=>"+resp);
isStop=true;
}else if(readResp<0){
//对端链路关闭
selectionKey.cancel();
socketChannel.close();
}else {
//读到0字节忽略
}
}
}
}
}
View Code
NIO比BIO的编程复杂度高,为什么应用却广泛使用?
- 网络连接I/O非阻塞:客户端的链接操作是异步的,可以通过在多路复用器注册OP_CONNECT等后续结果,不需要像BIO客户端那样被同步阻塞。
- 网络读写I/O非阻塞,异步化:SocketChannel的读写操作都是异步的,如果没有可读写的数据,它不会同步等待,直接返回。这样I/O通信线程就可以处理其他链路,不需要同步等待这个链路可用。
- 网络连接数无限制:线程模型优化:由于JDK的Selector在Liunx等主流操作系统上通过epoll实现,它没有句柄数的限制(只受限于操作系统的最大句柄数或者对单个进程的句柄限制),这意味着一个Selector线程可以同时处理成千上万个客户端连接,而且性能不会随着客户端的增加而线性下降。因此,它非常适合做高性能,高负载的网络服务器。
三、AIO写的时间服务器
1、server代码
package com.spring.test.service.netty.server.aio;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
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.concurrent.CountDownLatch;
/**
*
* @date 12:55 PM 2019/8/11
*/
public class AsyncTimeServerHandler implements Runnable {
private int port;
CountDownLatch countDownLatch;
AsynchronousServerSocketChannel asynchronousServerSocketChannel;
public static void main(String[] args) {
//启动时间服务器
Thread timerServer=new Thread(new AsyncTimeServerHandler(8080));
timerServer.start();
}
public AsyncTimeServerHandler(int port) {
this.port = port;
try {
asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open();
asynchronousServerSocketChannel.bind(new InetSocketAddress(port));
System.out.println("======The time server is start in port:" + port + "======");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
countDownLatch = new CountDownLatch(1);
doAccept();
try {
countDownLatch.await();
} catch (Exception e) {
e.printStackTrace();
}
}
public void doAccept() {
//获取客户单接入的请求
asynchronousServerSocketChannel.accept(this,new AcceptCompletionHandler());
}
}
/**
* 获取客户端连接的回调函数
*/
class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, AsyncTimeServerHandler> {
@Override
public void completed(AsynchronousSocketChannel result, AsyncTimeServerHandler attachment) {
//用于接收下一个客户端接入的请求
attachment.asynchronousServerSocketChannel.accept(attachment, this);
//处理当前请求
ByteBuffer buffer=ByteBuffer.allocate(1024);
result.read(buffer,buffer,new ReadCompletionHandler(result));
}
@Override
public void failed(Throwable exc, AsyncTimeServerHandler attachment) {
//接收请求失败,则把服务端关闭
exc.printStackTrace();
attachment.countDownLatch.countDown();
}
}
/**
* 读取连接的请求内容回调函数
*/
class ReadCompletionHandler implements CompletionHandler<Integer,ByteBuffer>{
private AsynchronousSocketChannel asynchronousSocketChannel;
public ReadCompletionHandler(AsynchronousSocketChannel asynchronousSocketChannel) {
this.asynchronousSocketChannel = asynchronousSocketChannel;
}
@Override
public void completed(Integer result, ByteBuffer attachment) {
attachment.flip();
byte[] requestBody=new byte[attachment.remaining()];
attachment.get(requestBody);
try {
String req=new String(requestBody,"UTF-8");
System.out.println("The time server receive order:"+req);
String currentTime="QUERY TIME ORDER".equals(req)? DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss"):"BAD ORDER";
doWrite(currentTime);
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
//关闭请求
try {
this.asynchronousSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void doWrite(String currentTime){
if(StringUtils.isNotBlank(currentTime)){
byte[] bytes=currentTime.getBytes();
ByteBuffer writeBuffer=ByteBuffer.allocate(bytes.length);
writeBuffer.put(bytes);
writeBuffer.flip();
asynchronousSocketChannel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
//如果没有发送完,则继续发送
if(attachment.hasRemaining()){
asynchronousSocketChannel.write(attachment,attachment,this);
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
//如果发送失败,则关闭channel
try {
asynchronousSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
}
View Code
2、client代码
package com.spring.test.service.netty.server.aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;
/**
* @author
* @date 2:33 PM 2019/8/11
*/
public class AsyncTimeClientHandler implements CompletionHandler<Void,AsyncTimeClientHandler>,Runnable{
private AsynchronousSocketChannel asynchronousSocketChannel;
private String host;
private int port;
private CountDownLatch countDownLatch;
public static void main(String[] args) {
//启动客户单发送请求
Thread timerClient=new Thread(new AsyncTimeClientHandler("127.0.0.1",8080));
timerClient.start();
}
public AsyncTimeClientHandler(String host,int port){
this.host=host;
this.port=port;
try {
asynchronousSocketChannel=AsynchronousSocketChannel.open();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
countDownLatch=new CountDownLatch(1);
asynchronousSocketChannel.connect(new InetSocketAddress(host,port),this,this);
try {
countDownLatch.await();
}catch (Exception e){
e.printStackTrace();
}
try {
asynchronousSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void completed(Void result, AsyncTimeClientHandler attachment) {
//连接成功,发送请求
byte[] req="QUERY TIME ORDER".getBytes();
ByteBuffer writeBuffer=ByteBuffer.allocate(req.length);
writeBuffer.put(req);
writeBuffer.flip();
asynchronousSocketChannel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
if(attachment.hasRemaining()){
//半包写,则继续发送,将请求数据完整发送给服务端
asynchronousSocketChannel.write(attachment,attachment,this);
}else{
//写成功了,则需要读取服务端响应
ByteBuffer readBuffer=ByteBuffer.allocate(1024);
asynchronousSocketChannel.read(readBuffer, readBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
//读取服务端响应成功
attachment.flip();
byte[] bytes=new byte[attachment.remaining()];
attachment.get(bytes);
String responseBody;
try {
//读取响应成功
responseBody=new String(bytes,"UTF-8");
System.out.println("Now is:"+responseBody);
//读取响应成功,关闭客户端连接
countDownLatch.countDown();
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
//读取服务端响应失败
try {
asynchronousSocketChannel.close();
countDownLatch.countDown();
}catch (Exception e){
e.printStackTrace();
}
}
});
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
//向服务端发送请求报文失败,关闭客户端
try {
asynchronousSocketChannel.close();
countDownLatch.countDown();
}catch (Exception e){
e.printStackTrace();
}
}
});
}
@Override
public void failed(Throwable exc, AsyncTimeClientHandler attachment) {
//向服务端发起连接失败
try {
asynchronousSocketChannel.close();
countDownLatch.countDown();
}catch (Exception e){
e.printStackTrace();
}
}
}
View Code
四、netty写时间服务器
jdkversion:1.8
nettyversion:5.0.0.Alpha1
1、server代码
package com.spring.test.service.netty.nettydemo.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @date 4:13 PM 2019/8/11
*/
public class TimerServer {
public static void main(String[] args) {
TimerServer timerServer=new TimerServer();
timerServer.bind(8080);
}
public void bind(int port){
//step1:配置服务端的NIO线程组(一个线程组用于服务端接收客户端连接,一个线程组用于进行socketChannel的网络读写)
EventLoopGroup bossGroup=new NioEventLoopGroup();
EventLoopGroup workerGroup=new NioEventLoopGroup();
try {
//netty用于启动NIO服务的辅助启动类,目的四降低服务端开发复杂度
ServerBootstrap serverBootstrap=new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.childHandler(new ChildChannelHandler());
//step2:绑定端口,同步等待成功
ChannelFuture f=serverBootstrap.bind(port).sync();
//step3:等待服务端监听端口关闭
f.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
//step4:优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
package com.spring.test.service.netty.nettydemo.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
/**
* @author
* @date 4:21 PM 2019/8/11
*/
public class ChildChannelHandler extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new TimerServerHandler());
}
}
package com.spring.test.service.netty.nettydemo.server;
import org.apache.commons.lang.time.DateFormatUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
/**
* @author
* @date 4:26 PM 2019/8/11
*/
public class TimerServerHandler extends ChannelHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//读取请求
ByteBuf buffer= (ByteBuf) msg;
byte[] req=new byte[buffer.readableBytes()];
buffer.readBytes(req);
String reqbody=new String(req,"utf-8");
System.out.println("The time server receive order:"+reqbody);
String currentTime="QUERY TIME ORDER".equals(reqbody)? DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss"):"BAD ORDER";
//请求响应
ByteBuf resp=Unpooled.copiedBuffer(currentTime.getBytes());
System.out.println("The time server resp order:"+currentTime);
//将相应结果,异步发送给客户端
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//将消息发送队列中的消息写入socketChannel中发送给对方。
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
View Code
2、client代码
package com.spring.test.service.netty.nettydemo.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* @author
* @date 5:41 PM 2019/8/11
*/
public class TimerClient {
public static void main(String[] args) throws InterruptedException {
TimerClient timerClient=new TimerClient();
timerClient.connect(8080,"127.0.0.1");
}
public void connect(int port,String host) throws InterruptedException {
//step1:配置NIO客户端线程组
EventLoopGroup group=new NioEventLoopGroup();
try {
Bootstrap bootstrap=new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimerClientHandler());
}
});
//发起异步连接操作(调用同步方法,等待连接成功)
ChannelFuture f=bootstrap.connect(host,port).sync();
//等待客户端链路关闭
f.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
//优雅的退出,释放NIO线程组
group.shutdownGracefully();
}
}
}
package com.spring.test.service.netty.nettydemo.client;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
/**
* @author
* @date 5:49 PM 2019/8/11
*/
public class TimerClientHandler extends ChannelHandlerAdapter {
private final ByteBuf firstMessage;
public TimerClientHandler(){
byte[] req="QUERY TIME ORDER".getBytes();
firstMessage= Unpooled.buffer(req.length);
firstMessage.writeBytes(req);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("释放资源");
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//发送请求
ctx.writeAndFlush(firstMessage);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//读取响应
ByteBuf buf= (ByteBuf) msg;
byte[] resp=new byte[buf.readableBytes()];
buf.readBytes(resp);
String responseBody=new String(resp,"utf-8");
System.out.println("Now time is:"+responseBody);
}
}
View Code