前言
在很多的网站中都嵌入有聊天功能,最理想的方式就是使用WebSocket来开发,屏幕面前的你如果不清楚WebSocket的作用可以自己去百度一下,Netty提供了WebSocket支持,这篇文章将使用Netty作为服务器,使用WebSocket开发一个简易的聊天室系统。
服务端导入依赖
io.netty
netty-all
4.1.42.Final
Netty提供了 WebSocketServerProtocolHandler ,它能够把平台的Http协议升级为WebSocket的WS协议,服务端代码如下
public class NettySocketServer {
public static void main(String[] args) {
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
try {
bootstrap.group(bossGroup, workGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer() {
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
//设置http编码器
pipeline.addLast(new HttpServerCodec());
//支持以块的方式写数据,添加块处理器
pipeline.addLast(new ChunkedWriteHandler());
//http请求是分段的,通过该处理器聚合分段
pipeline.addLast(new HttpObjectAggregator(8192));
//支持websocket长连接,添加SocketServer处理器,把http升级为ws协议
//客户端请求方式为:ws://localhost:8000/hello
pipeline.addLast(new WebSocketServerProtocolHandler("/hello"));
//处理请求,执行业务的Hnadler
pipeline.addLast(new MyWebSorcketServerHandler());
}
});
//启动服务器
ChannelFuture sync = bootstrap.bind(8000).sync();
sync.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
- 因为使用http,所以需要通过pipeline添加http编码器 HttpServerCodec
- WebSocketServerProtocolHandler : WebSocket支持,把http升级为ws协议
- MyWebSorcketServerHandler :该处理器是服务器处理请求的处理器
//消息进站处理 ,TextWebSocketFrame:WebSokcet消息是以“帧 Frame”的方式参数,该类是针对Text的数据
public class MyWebSorcketServerHandler extends SimpleChannelInboundHandler {
//保存所有客户端
private static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
private SimpleDateFormat dateFormat = new SimpleDateFormat("mm:ss");
//读取消息
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
String message = dateFormat.format(new Date())+":%s:"+msg.text();
System.out.println("收到消息: "+ctx.channel().remoteAddress()+":"+message);
String sendMsg = String.format(message, ctx.channel().remoteAddress());
//把消息广播给所有的客户端
channels.writeAndFlush(new TextWebSocketFrame(sendMsg));
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
String message = dateFormat.format(new Date())+":"+ctx.channel().remoteAddress()+" 加入聊天室";
//添加客户端的集合
channels.add(ctx.channel());
//自动把消息广播给其客户端
channels.writeAndFlush(new TextWebSocketFrame(message));
System.out.println("服务器收到链接 ID="+ctx.channel().id().asLongText());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
String message = dateFormat.format(new Date())+":"+ctx.channel().remoteAddress()+" 断开连接";
channels.writeAndFlush(new TextWebSocketFrame(message));
}
//客户端退出
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
String message = dateFormat.format(new Date())+":"+ctx.channel().remoteAddress()+" 退出聊天室";
channels.writeAndFlush(new TextWebSocketFrame(message));
System.out.println(message);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("发生异常 ID="+ctx.channel().id().asLongText()+";msg="+cause.getMessage());
ctx.channel().close();
}
}
- DefaultChannelGroup : 该group用来存储所有的客户端的channel
- channelRead0 : 当接收到请求拿到数据的方法,需要把数据广播给所有客户端
DOCTYPE html>
WebSocket测试
发送
var socket;
if(!window.WebSocket){
alert("浏览器不支持");
}else{
//创建客户端
socket = new window.WebSocket("ws://localhost:8000/hello");
//当收到消息
socket.onmessage = function (event) {
var input = document.getElementById("viewBody");
input.value = input.value +"\n"+event.data;
}
//打开链接
socket.onopen = function (event) {
var input = document.getElementById("viewBody");
input.value = "成功加入聊天室"+"\n";
}
//关闭链接
socket.onclose = function (event) {
var input = document.getElementById("viewBody");
input.value = input.value +"\n"+"退出聊天室";
}
function send(){
if(socket && socket.readyState == WebSocket.OPEN){
let sendInput = document.getElementById("sendInput");
let value = sendInput.value;
socket.send(value);
sendInput.value = "";
}
}
}
测试效果
文章结束,喜欢给个好评吧。