netty整合使用webscoket

上一篇我们简单说了一下netty的基本操作,其实在netty底层,提供了大量的支持服务端和客户端进行通讯的组件,比如像http协议,支持webscoket的整合等,可以很方便的进行使用,当然,我们也可以单纯的使用websocket进行客户端和服务端的通信,可根据业务场景和自己项目的情况进行选择,下面来实现一个通过页面发送消息到netty服务端,再有服务端推送消息给客户端的功能,

整个部分分为2步,我们先进行服务端代码编写,根据上一篇我们使用的经验,服务端启动主要包括三个类,1、初始化连接配置 2、自定义childHandler 3、自定义业务逻辑处理

1、pom依赖文件:

        
			io.netty
			netty-all
			5.0.0.Alpha2
			
		

2、netty初始化启动配置线程组信息:

package com.congge.sort.netty.day2;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * 服务端
 * @author asus
 *
 */
public class WssServer {
	
	public static void main(String[] args) {
		
		EventLoopGroup mainGroup = new NioEventLoopGroup();
		EventLoopGroup subGroup = new NioEventLoopGroup();
		
		try {
			ServerBootstrap server = new ServerBootstrap();
			server.group(mainGroup, subGroup)
					.channel(NioServerSocketChannel.class)
					.childHandler(new WssServerInitialzer());	//添加自定义初始化处理器
			ChannelFuture future = server.bind(8087).sync();
			future.channel().closeFuture().sync();
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			mainGroup.shutdownGracefully();
			subGroup.shutdownGracefully();
		}
	}
	
}	

3、WssServerInitialzer ,这个类主要配置相应的处理业务的前置信息,比如像和客户端通信,指定相应的通信协议,编码解码信息,自定义相关的handler,其实也可以放在一个代码块儿里面,netty这里使用的类似java设计模式中的责任链模式,可以将所有的自定义或者相关的handler串联起来,对应的就是 : pipeline.addLast ,可以为pipeline添加多个handler

package com.congge.sort.netty.day2;


import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

public class WssServerInitialzer extends ChannelInitializer{

	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
	
		ChannelPipeline pipeline = ch.pipeline();
		
		//websocket基于http协议,所以需要http编解码器
		pipeline.addLast(new HttpServerCodec());
		//添加对于读写大数据流的支持
		pipeline.addLast(new ChunkedWriteHandler());
		//对httpMessage进行聚合
		pipeline.addLast(new HttpObjectAggregator(1024*64));
		
		// ================= 上述是用于支持http协议的 ==============
		
		//websocket 服务器处理的协议,用于给指定的客户端进行连接访问的路由地址
		//比如处理一些握手动作(ping,pong)
		pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
		
		//自定义handler
		pipeline.addLast(new ChatHandler());
		
		
	}

}

4、下面是我们自定义的handler,这个里面要做的就是处理客户端发送过来的数据,解析数据,并将相应的服务端数据或者业务消息推送给客户端,同时这个类里面,我们可以通过调用netty提供的相应的API,及时捕获到客户端和服务端的连接信息,即所谓的生命周期,可以参照代码和调试的时候看出来,

package com.congge.sort.netty.day2;

import java.time.LocalDateTime;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * 聊天的ehandler
 * TextWebSocketFrame  用于为websockt处理文本的对象
 * @author asus
 *
 */
public class ChatHandler extends SimpleChannelInboundHandler{

	//用于记录和管理所有客户端的channel
	private static ChannelGroup clients = 
			new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
	
	@Override
	protected void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame msg) 
			throws Exception {
		//客户端传递过来的消息
		String content = msg.text();
		System.out.println("接收到了客户端的消息是:" + content);
		
		//将客户端发送过来的消息刷到所有的channel中
		for(Channel channel : clients){
			//channel.writeAndFlush(msg);	
			channel.writeAndFlush(
					new TextWebSocketFrame("[服务器接收到了客户端的消息:]" + LocalDateTime.now()+",消息为:" + content));
		}
		
//		clients.writeAndFlush(
//				new TextWebSocketFrame("[服务器接收到了客户端的消息:]" + LocalDateTime.now()+",消息为:" + content));
		
	}
	
	//客户端创建的时候触发,当客户端连接上服务端之后,就可以获取该channel,然后放到channelGroup中进行统一管理	
	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
		clients.add(ctx.channel());
	}
	
	//客户端销毁的时候触发,
	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
		//当handlerRemoved 被触发时候,channelGroup会自动移除对应的channel
		//clients.remove(ctx.channel());
		System.out.println("客户端断开,当前被移除的channel的短ID是:" +ctx.channel().id().asShortText());
	}
	

}

5、接下来是客户端代码编写,为了模拟的效果更真实,这里简单写了一个html页面,



	
		
		
	
	
		
		
发送消息
接收消息:

页面效果如图:
netty整合使用webscoket_第1张图片

我们重点关注一下里面的JS,其实就是创建了一个wensocket的对象,然后可以将文本框输入内容发送出去,

6、启动服务端,可以看到控制台输出了内容,表示连接服务端成功,然后我们再发送一条消息给服务端,
netty整合使用webscoket_第2张图片
服务端控制台收到了客户端的消息:
netty整合使用webscoket_第3张图片

同时服务端将消息推回给了客户端:
netty整合使用webscoket_第4张图片

这时我们断开服务端的连接,客户端捕捉到了连接断开的消息,当然,
netty整合使用webscoket_第5张图片

当然,如果我们关闭浏览器,服务端也可以看到捕捉到这个客户端连接断开的信息,利用netty的这种生命周期相关的API可以在此做一些比如聊天室好友上下线的提示等…
netty整合使用webscoket_第6张图片
到此,netty使用websocket基本结束,感谢观看!

你可能感兴趣的:(websocket,java)