public void send(String text) {
channel.writeAndFlush(Unpooled.copiedBuffer(text.getBytes()));
}
public void closeConnect() {
send(“bye”);
channel.close();
}
}
class MyHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = null;
try {
buf = (ByteBuf) msg;
byte[] bytes = new byte[buf.readableBytes()];
buf.getBytes(buf.readerIndex(), bytes);
String str = new String(bytes);
System.out.println(str);
System.out.println(buf.refCnt());
// 将数据更新到界面上
ClientFrame.INSTANCE.updateText(str);
} finally {
if (buf != null) {
ReferenceCountUtil.release(buf);
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
服务器:
====
package com.zy.nettychat;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.GlobalEventExecutor;
import java.util.Objects;
public class ChatServer {
// 负责装载所有的客户端chnnel,方便向客户端写数据
public static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
public static void main(String[] args) {
// 负责接客
EventLoopGroup bossGroup = new NioEventLoopGroup(2);
// 负责服务
EventLoopGroup workerGroup = new NioEventLoopGroup(4);
// 服务类
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
// netty帮我们内部处理了accept过程
bootstrap.childHandler(new MyServerChildInitializer());
try {
ChannelFuture channelFuture = bootstrap.bind(8888).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
class MyServerChildInitializer extends ChannelInitializer {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new MyChildHandler());
System.out.println(“a client connected !”);
}
}
class MyChildHandler extends ChannelInboundHandlerAdapter {
// 表示客户端通道可用,因此在这里面添加客户端chnnel
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ChatServer.clients.add(ctx.channel());
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
byte[] bytes = new byte[buf.readableBytes()];
buf.getBytes(buf.readerIndex(), bytes);
String str = new String(bytes);
System.out.println(“客户端数据:” + str);
if (Objects.equals(str, “bye”)) {
System.out.println(“client ready to quit”);
ChatServer.clients.remove(ctx.channel()); // 会自动释放buf,不需要显式关闭
ctx.close();
} else {
ChatServer.clients.writeAndFlush(msg);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ChatServer.clients.remove(ctx.channel());
cause.printStackTrace();
ctx.close();
}
}
Encoder和Decoder
===============
例如将坦克的位置传输给服务器,可以有两种方式:
第一种:
“30,20”.getBytes() ->服务器
第二种:
30->[0100110011011…] 32位字节数组
20->[…] 32位字节数组
将8byte send to Server->
两种方式哪种更好???
第二种最好
字符串长度不固定,编码不固定,甚至语言不固定。并且转字符串效率比较低。(为什么低呢???)
编码器和解码器由Netty自动识别调用,不用担心在需要Encoder时会误调用Decoder,也不用担心在需要Decoder时误用encoder
多种不同的编解码器可以混在一起使用共同实现程序的业务逻辑。
定义消息
package com.zy.nettycoder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Setter
@Getter
@ToString
public class TankMsg {
private int x;
private int y;
public TankMsg(int x, int y) {
this.x = x;
this.y = y;
}
}
客户端:
package com.zy.nettycoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
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;
import io.netty.util.ReferenceCountUtil;
public class TankClient {
private Channel channel;
public void connect() {
// 负责服务
EventLoopGroup workerGroup = new NioEventLoopGroup(4);
// 服务类
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(workerGroup);
bootstrap.channel(NioSocketChannel.class);
// netty帮我们内部处理了accept过程
bootstrap.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
channel = socketChannel;
socketChannel.pipeline()
.addLast(new TankMsgEncoder()) // 天添加编码器,貌似必 须在handler之前啊!!!
.addLast(new TankMsgClientHandler());
}
});
try {
ChannelFuture channelFuture = bootstrap.connect(“localhost”, 8888).sync();
// closeFuture表示如果有人调用了channel的close的方法,那么才会拿到close的future
// 如果没有关,就会阻塞到这里
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
}
}
public void send(String text) {
channel.writeAndFlush(Unpooled.copiedBuffer(text.getBytes()));
}
public void closeConnect() {
send(“bye”);
channel.close();
}
}
class TankMsgClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(new TankMsg(5, 8));
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = null;
try {
buf = (ByteBuf) msg;
byte[] bytes = new byte[buf.readableBytes()];
buf.getBytes(buf.readerIndex(), bytes);
String str = new String(bytes);
System.out.println(str);
System.out.println(buf.refCnt());
} finally {
if (buf != null) {
ReferenceCountUtil.release(buf);
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
public static void main(String[] args) {
new TankClient().connect();
}
}
定义编码器:
package com.zy.nettycoder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
public class TankMsgEncoder extends MessageToByteEncoder {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, TankMsg tankMsg, ByteBuf byteBuf) throws Exception {
byteBuf.writeInt(tankMsg.getX());
byteBuf.writeInt(tankMsg.getY());
}
}
定义服务器:
package com.zy.nettycoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.GlobalEventExecutor;
public class TankMsgServer {
// 负责装载所有的客户端chnnel,方便向客户端写数据
public static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
public static void serverStart() {
// 负责接客
EventLoopGroup bossGroup = new NioEventLoopGroup(2);
// 负责服务
EventLoopGroup workerGroup = new NioEventLoopGroup(4);
// 服务类
ServerBootstrap bootstrap = new ServerBootstrap();
// 异步全双工
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
// netty帮我们内部处理了accept过程
bootstrap.childHandler(new TankMsgServerChildInitializer());
try {
ChannelFuture channelFuture = bootstrap.bind(8888).sync();
TankMsgServerFrame.INSTANCE.updateServerMsg(“server started!”);
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
class TankMsgServerChildInitializer extends ChannelInitializer {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline()
.addLast(new TankMsgDecoder())
.addLast(new TankMsgChildHandler());
System.out.println(“a client connected !”);
}
}
class TankMsgChildHandler extends ChannelInboundHandlerAdapter {
// 表示客户端通道可用,因此在这里面添加客户端chnnel
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
TankMsgServer.clients.add(ctx.channel());
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(“开始读取数据!!!”);
TankMsg tankMsg = (TankMsg) msg;
TankMsgServerFrame.INSTANCE.updateClientMsg(tankMsg.toString());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
TankMsgServer.clients.remove(ctx.channel());
cause.printStackTrace();
ctx.close();
}
}
定义解码器:
package com.zy.nettycoder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
public class TankMsgDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) throws Exception {
System.out.println(“TankMsgDecoder1111”);
if (byteBuf.readableBytes() < 8) {
return;
}
int x = byteBuf.readInt();
int y = byteBuf.readInt();
list.add(new TankMsg(x, y));
}
}
定义服务器界面:
package com.zy.nettycoder;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class TankMsgServerFrame extends Frame {
public static final TankMsgServerFrame INSTANCE = new TankMsgServerFrame();
private TextArea taServer = new TextArea();
private TextArea taClient = new TextArea();
public TankMsgServerFrame() throws HeadlessException {
this.setSize(800, 600);
this.setLocation(300, 30);
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
lic static final TankMsgServerFrame INSTANCE = new TankMsgServerFrame();
private TextArea taServer = new TextArea();
private TextArea taClient = new TextArea();
public TankMsgServerFrame() throws HeadlessException {
this.setSize(800, 600);
this.setLocation(300, 30);
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-xKlpof98-1714933325589)]
[外链图片转存中…(img-wVqKnp3H-1714933325589)]
[外链图片转存中…(img-lSZ6EwCS-1714933325590)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!