Netty入门程序(四)
maven创建project,引入依赖:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.39.Final</version>
</dependency>
一、服务端程序
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
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.NioServerSocketChannel; public class Server4HelloWorld {
//监听线程组,监听客户端请求
private EventLoopGroup acceptorGroup = null;
//处理客户端相关操作线程组,负责处理与客户端的数据通讯
private EventLoopGroup clientGroup = null;
//服务启动相关配置信息
private ServerBootstrap bootstrap = null; public Server4HelloWorld(){
acceptorGroup = new NioEventLoopGroup();
clientGroup = new NioEventLoopGroup();
bootstrap = new ServerBootstrap();
//绑定线程组
bootstrap.group(acceptorGroup, clientGroup);
//设置通讯模式为NIO
bootstrap.channel(NioServerSocketChannel.class);
//设置服务端可连接队列的大小
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
//SO_SNDBUF发送缓冲区,SO_RCVBUF接收缓冲区, SO_KEEPALIVE 开启心跳监测(保证连接有效)
bootstrap.option(ChannelOption.SO_SNDBUF, 16*1024)
.option(ChannelOption.SO_RCVBUF, 16*1024)
.option(ChannelOption.SO_KEEPALIVE, true);
} public ChannelFuture doAccept(int port, final ChannelHandler... acceptHandlers) throws InterruptedException{
/*
* childHandler是ServerBootstrap独有的方法,是用于提供处理对象的。
* 可以一次性增加若干个处理逻辑,类似责任链的处理方式。
* 增加A、B两个逻辑,在处理客户端请求数据的时候,根据A->B顺序依次处理。
*
* ChannelInitializer 用于提供处理器的一个模型对象
* 其中定义了一个initChannel方法,用于处理逻辑责任链条的。
* 可以保证ServerBootstrap只初始化依次处理器,尽量提供处理逻辑的重用,
* 避免反复的创建处理器对象,节约资源开销
*/
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(acceptHandlers);
};
});
//bind方法 - 绑定监听端口。ServerBootstrap可以绑定多个监听端口,多次调用bind方法即可。
//sync -- 开始监听逻辑,返回一个ChannelFuture,代表的是监听成功后一个对应的未来结果
//可以使用ChannelFuture用于后续的处理逻辑
ChannelFuture future = bootstrap.bind(port).sync();
return future;
} /*
* shutdownGracefully 是一个安全关闭的方法,可以保证不放弃任何一个已接收的客户端请求
*/
public void release(){
this.acceptorGroup.shutdownGracefully();
this.clientGroup.shutdownGracefully();
} public static void main(String[] args) {
ChannelFuture future = null;
Server4HelloWorld server = null;
try {
server = new Server4HelloWorld();
future = server.doAccept(9999, new Server4HelloWorldHandler());
System.out.println("server started");
//关闭连接
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}finally {
if(null != future){
try {
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(null != server){
server.release();
}
}
} }
Handler处理逻辑:
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelHandler.Sharable; /*
* @Sharable注解
* 代表当前Handler是一个可以共享的处理器,也就是意味着,服务器注册此Handler后,可以给多个客户端同时使用。
* 如果不使用注解描述类型,则每次客户端请求时,必须为客户端重新创建一个新的Handler对象(实际开发中,推荐共享一个Handler,节约内存资源)。
* 如果Handler是一个Sharable的,一定避免定义可写的实例变量,因为这不安全。
* bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new XxxHandler());
};
}); */ @Sharable
public class Server4HelloWorldHandler extends ChannelInboundHandlerAdapter{ /*
* 业务处理逻辑
* 用于处理读取数据请求的逻辑
* ctx - 上下文对象,其中包含客户端建立连接的所有资源,如:对应的Channel
* msg - 读取到的数据,默认类型是ByteBuf,ByteBuf是Netty自定义的,是对ByteBuffer的封装
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//获取读取的数据,是一个缓冲
ByteBuf readBuffer = (ByteBuf)msg;
//创建一个字节数组,用于保存缓冲中的数据
byte[] tempDatas = new byte[readBuffer.readableBytes()];
//将缓存中的数据读取到字节数组中
readBuffer.readBytes(tempDatas);
String message = new String(tempDatas, "UTF-8");
System.out.println("from client:" + message);
if("exit".equals(message)){
ctx.close();
return;
}
String line = "server message to client";
//写操作自动释放缓存,避免内存溢出问题
ctx.writeAndFlush(Unpooled.copiedBuffer(line.getBytes("UTF-8")));
//注意,如果使用的是write方法,不会刷新缓存,缓存中的数据不会发送到客户端,必须再次调用flush方法才行
//ctx.write(Unpooled.copiedBuffer(line.getBytes("UTF-8")));
//ctx.flush();
} /**
* 异常处理逻辑,当客户端异常退出的时候,也会运行
* ChannelHandlerContext 关闭,也代表当前与客户端连接的资源关闭
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println(" server exceptionCaught method run...");
ctx.close();
} }
二、客户端程序
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; /**
* 因为客户端是请求的发起者,不需要监听。
* 只需要定义唯一的一个线程组即可。
*/
public class Client4HelloWorld { //处理请求和服务端响应的线程组
private EventLoopGroup group = null;
//服务启动相关配置信息
private Bootstrap bootstrap; public Client4HelloWorld(){
group = new NioEventLoopGroup();
bootstrap = new Bootstrap();
//绑定线程组
bootstrap.group(group);
//设定通讯模式为NIO
bootstrap.channel(NioSocketChannel.class);
} public ChannelFuture doRequest(String host, int port, final ChannelHandler... handlers) throws InterruptedException{
/*
* 客户端的Bootstrap没有childHandler方法,只有handler方法。
* 等同于ServerBootstrap的childHandler方法
* 在客户端必须绑定处理器,即必须调用handler方法
* 在服务端必须绑定处理器,即必须调用childHandler方法
*/
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(handlers);
};
});
//建立连接
ChannelFuture future = bootstrap.connect(host, port).sync();
return future;
} public void release(){
this.group.shutdownGracefully();
} public static void main(String[] args) {
Client4HelloWorld client = null;
ChannelFuture future = null;
try {
client = new Client4HelloWorld();
future = client.doRequest("localhost", 9999, new Client4HelloWorldHandler());
Scanner s = null;
while(true){
s = new Scanner(System.in);
System.out.println("enter message send to server (enter 'exit' for close client)...>>");
String line = s.nextLine(); if("exit".equals(line)){
//addListener -- 增加监听,当某条件满足的时候,触发监听器
//ChannelFutureListener.CLOSE 代表ChannelFuture执行返回后,关闭连接
future.channel().writeAndFlush(Unpooled.copiedBuffer(line.getBytes("UTF-8")))
.addListener(ChannelFutureListener.CLOSE);
break;
}
future.channel().writeAndFlush(Unpooled.copiedBuffer(line.getBytes("UTF-8")));
TimeUnit.SECONDS.sleep(1);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(future != null){
try {
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(client != null){
client.release();
}
}
}
}
Handler处理逻辑:
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil; public class Client4HelloWorldHandler extends ChannelInboundHandlerAdapter{ @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
ByteBuf readBuffer = (ByteBuf)msg;
byte[] tempDatas = new byte[readBuffer.readableBytes()];
readBuffer.readBytes(tempDatas);
System.out.println("from server :" + new String(tempDatas, "UTF-8"));
} finally {
//用于释放缓存,避免内存溢出
ReferenceCountUtil.release(msg);
}
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("client exceptionCaught method run ...");
}
}
Netty入门程序(四)的更多相关文章
- Netty权威指南之Netty入门程序
package com.hjp.netty.netty; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Chan ...
- Netty(一)——Netty入门程序
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7447618.html 有兴趣的可先了解下:4种I/O的对比与选型 主要内容包括: Netty开发环境的搭建 ...
- Netty入门(四)ByteBuf 字节级别的操作
Netty 中使用 ByteBuf 代替 Java NIO 提供的 ByteBuffer 作为字节的容器. 一.索引 ByteBuf 提供两个指针变量支持读和写操作,读操作使用 readerInde ...
- OpenGL入门程序四:颜色模式
1.OpenGL支持两种颜色模式: 1>RGBA颜色模式 ,用 glClearColor 指定清空屏幕后的颜色,即“空颜色” . 2>索引颜色模式,用 glClearIndex 指定清空屏 ...
- Netty入门二:开发第一个Netty应用程序
Netty入门二:开发第一个Netty应用程序 时间 2014-05-07 18:25:43 CSDN博客 原文 http://blog.csdn.net/suifeng3051/article/ ...
- Netty入门之HelloWorld
Netty系列入门之HelloWorld(一) 一. 简介 Netty is a NIO client server framework which enables quick and easy de ...
- Netty入门
一.NIO Netty框架底层是对NIO的高度封装,所以想要更好的学习Netty之前,应先了解下什么是NIO - NIO是non-blocking的简称,在jdk1.4 里提供的新api,他的他的特性 ...
- Netty入门教程——认识Netty
什么是Netty? Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架. Netty 是一个广泛使用的 Java 网络编程框架(N ...
- Java网络编程 -- Netty入门
Netty简介 Netty是一个高性能,高可扩展性的异步事件驱动的网络应用程序框架,它极大的简化了TCP和UDP客户端和服务器端网络开发.它是一个NIO框架,对Java NIO进行了良好的封装.作为一 ...
随机推荐
- springboot集成freemarker属性配置(不知道是针对于某个版本,2.0后有变动)
freemarker属性配置 freemarker属性配置: spring.freemarker.allow-request-override=false # 设置是否允许HttpServletReq ...
- Django middleware (中间件)
关于中间价: django 中的中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法. 在django项目的settings中,有一个 MIDDLE ...
- AGC008E Next or Nextnext(组合计数,神奇思路)
神仙题. 排列计数,一种常见的做法是 \(i\) 向 \(p_i\) 连边. 然而这里这个就逼迫我们只能从 \(i\) 向 \(a_i\) 连边. 不过没关系,考虑从 \(i\) 向 \(p_i\) ...
- 第04组 Alpha冲刺(4/6)
队名:new game 组长博客:戳 作业博客:戳 组员情况 鲍子涵(队长) 燃尽图 过去两天完成了哪些任务 才两天,也就是实现一些功能而已 复习 接下来的计划 实现更多的功能 为这周的比赛准备 还剩 ...
- Azure EA (2) 使用Postman访问国内Azure Billing API
<Windows Azure Platform 系列文章目录> 本文介绍的是国内由世纪互联运维的Azure China 请读者先看一下之前的文档内容:Azure EA (1) 查看国内Az ...
- client-go客户端自定义开发Kubernetes及源码分析
介绍 client-go 是一种能够与 Kubernetes 集群通信的客户端,通过它可以对 Kubernetes 集群中各资源类型进行 CRUD 操作,它有三大 client 类,分别为:Clien ...
- umi+dva+antd新建项目
首先全局安装dva+umiumi:npm install -g umidva:npm install -g dva-cli 通过脚手架创建项目 一: mkdir myapp && cd ...
- LeetCode 557:反转字符串中的单词 III Reverse Words in a String III
公众号:爱写bug(ID:icodebugs) 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序. Given a string, you need to reve ...
- redis之GeoHash
Redis 提供的 Geo 指令只有 6 个,它只是一个普通的 zset 结构. 增加geoadd 指令携带集合名称以及多个经纬度名称三元组,注意这里可以加入多个三元组127.0.0.1:6379&g ...
- 奥展项目笔记05--域名、端口、Nginx相关知识笔记
1.我国的电信运营商是默认封闭80端口的. 中国电信屏蔽ADSL用户80端口 只是做应用服务器的话你可以使用别的端口. 80端口电脑上同时有各种各样的程序在运行,他们都需要借助网络来进行通信.例如,你 ...