Netty5 服务端和客户端-copy
概述
netty 5 已经放弃掉了,作为学习netty4和5的差别不大,本例子是基于netty5
https://github.com/netty/netty/issues/4466
线程安全
一个thread + 队列 == 一个单线程线程池。线程安全的,任务是线性串行执行的
线程安全,不会产生阻塞效应 ,使用对象组
线程不安全,会产生阻塞效应, 使用对象池
Figure 1. 对象池
Figure 2. 对象组
writeAndFlush 发送消息线程安全
其中 EventExecutor executor 是 NioEventLoop 线程安全
public final class NioEventLoop extends SingleThreadEventLoop
代码
Server
/**
* netty5服务端
*
*
*/
public class Server {
public static void main(String[] args) {
//服务类
ServerBootstrap bootstrap = new ServerBootstrap();
//boss和worker
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
//设置线程池
bootstrap.group(boss, worker);
//设置socket工厂、
bootstrap.channel(NioServerSocketChannel.class);
//设置管道工厂
bootstrap.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new ServerHandler());
}
});
//netty3中对应设置如下
//bootstrap.setOption("backlog", 1024);
//bootstrap.setOption("tcpNoDelay", true);
//bootstrap.setOption("keepAlive", true);
//设置参数,TCP参数
bootstrap.option(ChannelOption.SO_BACKLOG, 2048);//serverSocketchannel的设置,链接缓冲池的大小
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);//socketchannel的设置,维持链接的活跃,清除死链接
bootstrap.childOption(ChannelOption.TCP_NODELAY, true);//socketchannel的设置,关闭延迟发送
//绑定端口
ChannelFuture future = bootstrap.bind(10101);
System.out.println("start");
//等待服务端关闭
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally{
//释放资源
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
ServerHandler
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* 服务端消息处理
*
*
*/
public class ServerHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(msg);
ctx.channel().writeAndFlush("hi");
ctx.writeAndFlush("hi");
}
/**
* 新客户端接入
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive");
}
/**
* 客户端断开
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelInactive");
}
/**
* 异常
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
}
Client
import java.io.BufferedReader;
import java.io.InputStreamReader;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* netty5的客户端
*
*
*/
public class Client {
public static void main(String[] args) {
//服务类
Bootstrap bootstrap = new Bootstrap();
//worker
EventLoopGroup worker = new NioEventLoopGroup();
try {
//设置线程池
bootstrap.group(worker);
//设置socket工厂、
bootstrap.channel(NioSocketChannel.class);
//设置管道
bootstrap.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture connect = bootstrap.connect("127.0.0.1", 10101);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
while(true){
System.out.println("请输入:");
String msg = bufferedReader.readLine();
connect.channel().writeAndFlush(msg);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
worker.shutdownGracefully();
}
}
}
ClientHandler
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* 客户端消息处理
*
*
*/
public class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("客户端收到消息:"+msg);
}
}
多连接客户端
MultClient
其中 synchronized(channel) 可以采用 单任务队列的方式
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* 多连接客户端
*
*
*/
public class MultClient {
/**
* 服务类
*/
private Bootstrap bootstrap = new Bootstrap();
/**
* 会话
*/
private List<Channel> channels = new ArrayList<>();
/**
* 引用计数
*/
private final AtomicInteger index = new AtomicInteger();
/**
* 初始化
* @param count
*/
public void init(int count){
//worker
EventLoopGroup worker = new NioEventLoopGroup();
//设置线程池
bootstrap.group(worker);
//设置socket工厂、
bootstrap.channel(NioSocketChannel.class);
//设置管道
bootstrap.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new ClientHandler());
}
});
for(int i=1; i<=count; i++){
ChannelFuture future = bootstrap.connect("192.168.0.103", 10101);
channels.add(future.channel());
}
}
/**
* 获取会话
* @return
*/
public Channel nextChannel(){
return getFirstActiveChannel(0);
}
private Channel getFirstActiveChannel(int count){
Channel channel = channels.get(Math.abs(index.getAndIncrement() % channels.size()));
if(!channel.isActive()){
//重连
reconnect(channel);
if(count >= channels.size()){
throw new RuntimeException("no can use channel");
}
return getFirstActiveChannel(count + 1);
}
return channel;
}
/**
* 重连
* @param channel
*/
private void reconnect(Channel channel){
synchronized(channel){
if(channels.indexOf(channel) == -1){
return ;
}
Channel newChannel = bootstrap.connect("192.168.0.103", 10101).channel();
channels.set(channels.indexOf(channel), newChannel);
}
}
}
Start
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* 启动类
*
*
*/
public class Start {
public static void main(String[] args) {
MultClient client = new MultClient();
client.init(5);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
while(true){
try {
System.out.println("请输入:");
String msg = bufferedReader.readLine();
client.nextChannel().writeAndFlush(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
netty心跳-copy
概述
心跳对于服务端来说,定时清除闲置会话inactive(netty5) channelclose(netty3)
心跳对客户端来说,用来检测会话是否断开,是否重连! 用来检测网络延时!
netty3
package com.heart;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.HashedWheelTimer;
/**
* netty服务端入门
*/
public class Server {
public static void main(String[] args) {
//服务类
ServerBootstrap bootstrap = new ServerBootstrap();
//boss线程监听端口,worker线程负责数据读写
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService worker = Executors.newCachedThreadPool();
//设置niosocket工厂
bootstrap.setFactory(new NioServerSocketChannelFactory(boss, worker));
final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer();
//设置管道的工厂
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("idle", new IdleStateHandler(hashedWheelTimer, 5, 5, 10));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("helloHandler", new HelloHandler());
return pipeline;
}
});
bootstrap.bind(new InetSocketAddress(10101));
System.out.println("start!!!");
}
}
package com.heart;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.handler.timeout.IdleState;
import org.jboss.netty.handler.timeout.IdleStateEvent;
public class HelloHandler extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println(e.getMessage());
}
@Override
public void handleUpstream(final ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof IdleStateEvent) {
if (((IdleStateEvent) e).getState() == IdleState.ALL_IDLE) {
System.out.println("提玩家下线");
//关闭会话,踢玩家下线
ChannelFuture write = ctx.getChannel().write("time out, you will close");
write.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
ctx.getChannel().close();
}
});
}
} else {
super.handleUpstream(ctx, e);
}
}
}
netty 5
package com.heart;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
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.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
/**
* netty5服务端
*/
public class Server {
public static void main(String[] args) {
//服务类
ServerBootstrap bootstrap = new ServerBootstrap();
//boss和worker
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
//设置线程池
bootstrap.group(boss, worker);
//设置socket工厂、
bootstrap.channel(NioServerSocketChannel.class);
//设置管道工厂
bootstrap.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new IdleStateHandler(5, 5, 10));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new ServerHandler());
}
});
//netty3中对应设置如下
//bootstrap.setOption("backlog", 1024);
//bootstrap.setOption("tcpNoDelay", true);
//bootstrap.setOption("keepAlive", true);
//设置参数,TCP参数
bootstrap.option(ChannelOption.SO_BACKLOG, 2048);//serverSocketchannel的设置,链接缓冲池的大小
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);//socketchannel的设置,维持链接的活跃,清除死链接
bootstrap.childOption(ChannelOption.TCP_NODELAY, true);//socketchannel的设置,关闭延迟发送
//绑定端口
ChannelFuture future = bootstrap.bind(10101);
System.out.println("start");
//等待服务端关闭
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
package com.heart;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
/**
* 服务端消息处理
*
*
*/
public class ServerHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(msg);
ctx.channel().writeAndFlush("hi");
ctx.writeAndFlush("hi");
}
@Override
public void userEventTriggered(final ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state() == IdleState.ALL_IDLE) {
//清除超时会话
ChannelFuture writeAndFlush = ctx.writeAndFlush("you will close");
writeAndFlush.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
ctx.channel().close();
}
});
}
} else {
super.userEventTriggered(ctx, evt);
}
}
/**
* 新客户端接入
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive");
}
/**
* 客户端断开
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelInactive");
}
/**
* 异常
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
Netty5 服务端和客户端-copy的更多相关文章
- (转)SVN 服务端、客户端安装及配置、导入导出项目
SVN服务器搭建和使用(一) Subversion是优秀的版本控制工具,其具体的的优点和详细介绍,这里就不再多说. 首先来下载和搭建SVN服务器. 现在Subversion已经迁移到apache网站上 ...
- Unity使用C#实现简单Scoket连接及服务端与客户端通讯
简介: 网络编程是个很有意思的事情,偶然翻出来很久之前刚开始看Socket的时候写的一个实例,贴出来吧 Unity中实现简单的Socket连接,c#中提供了丰富的API,直接上代码. 服务端代码: [ ...
- asp.net获取服务端和客户端信息
asp.net获取服务端和客户端信息 获取服务器名:Page.Server.ManchineName获取用户信息:Page.User 获取客户端电脑名:Page.Request.UserHostNam ...
- python thrift 服务端与客户端使用
一.简介 thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, ...
- IE8下服务端获取客户端文件的路径为C:/fakePath问题的解决方案
上一篇文章上提到,IE8下服务端获取客户端文件的路径时,会变成C:/fakePath问题,于是乎通过文件路径去获得文件大小就失败了. 上网搜了一下,主要原因是IE8因为安全考虑,在上传文件时屏蔽了真实 ...
- 如何排查APP服务端和客户端是否支持ATS
服务端排查 取得客户端直接连接的服务端域名及端口,例如mob.com.cn,端口443,即HTTPS默认端口.针对公网可访问的生产环境地址,建议使用的在线监测工具.https://wosign.ssl ...
- linux(centos 6.4)下安装php memcache服务端及其客户端(详细教程)
前言 在搭建个人博客时,由于没有使用任何框架,纯手工code前台和后台,导致遇到许多问题,其中一个问题就是mysql连接导致的页面相应速度异常低.在查询各种途径后,只能考虑使用memcache缓存.在 ...
- [C语言]一个很实用的服务端和客户端进行TCP通信的实例
本文给出一个很实用的服务端和客户端进行TCP通信的小例子.具体实现上非常简单,只是平时编写类似程序,具体步骤经常忘记,还要总是查,暂且将其记下来,方便以后参考. (1)客户端程序,编写一个文件clie ...
- 使用Apache CXF开发WebServices服务端、客户端
在前一篇的博客中,我使用Xfire1.x来开发了WebServies的服务端. 但是如果你访问Apache的官网,可以看到xfire已经被合并了. 最新的框架叫做CXF. Apache CXF = C ...
- 自定义Attribute 服务端校验 客户端校验
MVC 自定义Attribute 服务端校验 客户端校验/* GitHub stylesheet for MarkdownPad (http://markdownpad.com) *//* Autho ...
随机推荐
- 【2024.09.27】NOIP2024 赛前集训-刷题训练(3)
[2024.09.27]NOIP2024 赛前集训-刷题训练(3) NOIP2018 提高组 铺设道路 算法一:模拟正常人铺路的过程,每次找区间的最小值,最小值就是本次填的高度,由于出现了若干个0位置 ...
- Trie树练习题
Trie树练习题 T1 「一本通 2.3 例 2」The XOR Largest Pair 在给定的 \(N\) 个整数\(A_1,A_2,...A_N\)中选出两个进行异或运算,得到的结果最大是多少 ...
- Qt Creator快捷键记录
Ctrl + K:代码格式化(先选中要格式化的代码) F4:在头文件和源文件之间切换 Ctrl+/:注释和取消注释 F2:在声明和实现之间切换 Ctrl+K:打开定位器(locator),搜索文件名 ...
- 5.6 Linux Vim撤销和恢复撤销快捷键
使用 Vim 编辑文件内容时,经常会有如下 2 种需求: 对文件内容做了修改之后,却发现整个修改过程是错误或者没有必要的,想将文件恢复到修改之前的样子. 将文件内容恢复之后,经过仔细考虑,又感觉还是刚 ...
- 在 Github Action 管道内集成 Code Coverage Report
Github Actions 我们的开源项目 Host 在 Github,并且使用它强大的 Actions 功能在做 CICD.单看 Github Actions 可能不知道是啥.其实它就是我们常说的 ...
- 这可能是最好的Spring教程!即便无基础也能看懂的入门Spring,仍在持续更新。
开启这样一个系列的原因 这一段时间都在学spring,但是在学习的过程中一直都很难找到一个通俗易懂,又带了学习体系的文章教程,很多地方都不懂,需要自己去慢慢查询和理解,感觉学起来很耗时,所以我自己就像 ...
- python实现的扫雷游戏的AI解法(启发式算法)
相关: python编写的扫雷游戏 如何使用计算机程序求解扫雷游戏 本文中实现的<扫雷>游戏的AI解法的项目地址: https://openi.pcl.ac.cn/devilmaycry8 ...
- Git之清除历史记录操作
近期公司需要将之前代码仓库中的提交记录都清理,所以操作一下,记录一下步骤: 安全考虑: 有时候在提交代码时,不小心提交了敏感数据,如账号密码什么的,这样在历史记录中就可以查看到,这样很不安全,所以就需 ...
- Mybatis 实现多字段动态排序
背景 在项目的开发过程中,可能会遇到对数据表多个字段进行排序的需求(第一句话就这么难懂,不要害怕,万事开头难,结尾更难,开玩笑哒),结合需求轻松易懂. 需求 现在有一张User表 男同学先按 age ...
- docker 打包镜像过程
1.首先准备需要打成镜像的JAR包 2.编制Dockerfile文件 FROM docker.gf.com.cn/java:openjdk-8u292-arm64 MAINTAINER 8627905 ...