netty在socket编程中的作用:
- socket开发,可以开发客户端和服务端,微服务开发底层也是用netty来进行数据传输
- Netty可以支持长连接开发,http连接可以称之为短连接,服务端向客户端推送消息就需要使用websocket。如果是用netty可以只传送所需的数据,还可以自定义协议开发。定义请求头,请求体,请求格式,请求结尾什么
如下案例将展示netty服务端与多个客户端进行socket通讯
服务端代码:
public class MyChatServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try{
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new MyChatServerInitializer());
ChannelFuture future = bootstrap.bind(8899).sync();
future.channel().closeFuture().sync();
}finally{
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
MyChatServerInitializer.java
public class MyChatServerInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//DelimiterBasedFrameDecoder :netty定制的解码器,主要根据分隔符进行解析
pipeline.addLast(new DelimiterBasedFrameDecoder(4096,Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new MyChatServerHandler());//对于一对多的链接方式的处理
}
}
MyChatServerHandler.java
/**
* 消息广播的实现
* 服务器启动 然后会有多个用户与服务器进行建立连接 且服务端会打印出***已经上线
* 并且会在其他客户端打印出***上线
* 如果客户端断开与服务器的链接,则会在控制台中输出***下线,同时广播其他客户端***已经下线
*/
public class MyChatServerHandler extends SimpleChannelInboundHandler<String> {
//channelGroup:保存所有与服务器端链接的客户端的channel对象
private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
protected void channelRead0(ChannelHandlerContext ctx, String msg)
throws Exception {
Channel channel = ctx.channel(); //发送消息的channel对象
//把自己挑出来
channelGroup.forEach(ch->{
if(channel != ch){ //不是自己
ch.writeAndFlush(channel.remoteAddress() +"发送的消息: "+msg+"\n");
}else{
//是自己
ch.writeAndFlush("【自己】"+msg + "\n");
}
});
}
@Override//链接建立
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel(); //链接对象
//广播 服务端保存所有链接对象
//channelGroup 中的writeAndFlush方法会将内容写入到所有的channel中
channelGroup.writeAndFlush("[服务器-]"+channel.remoteAddress()+ "加入\n");
channelGroup.add(channel);
}
@Override //链接断了
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
//如果该链接断了,那么netty会自动将这个channel移除出channelGroup
channelGroup.writeAndFlush("[服务器]-"+channel.remoteAddress()+"离开\n");
System.out.println(channelGroup.size());
}
@Override //活动状态
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress() +"-已经上线了");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress()+"-已经下线了");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客户端的实现:
MyChatClientServer.java
public class MyChatClientServer {
public static void main(String[] args) throws Exception {
EventLoopGroup eventGroup = new NioEventLoopGroup();
try{
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventGroup).channel(NioSocketChannel.class)
.handler(new MyChatClientInitializer());
Channel channel = bootstrap.connect("localhost",8899).sync().channel();
//读取控制台输入的内容
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//死循环,等待键盘输入
for(;;){
channel.writeAndFlush(br.readLine()+"\r\n");
}
}finally{
eventGroup.shutdownGracefully();
}
}
}
MyChatClientInitializer.java
public class MyChatClientInitializer extends ChannelInitializer<SocketChannel> {
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(4096,Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new MyChatClientHandler());
};
}
MyChatClientHandler.java
public class MyChatClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg)
throws Exception {
System.out.println(msg);
}
}