版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/qq_37372007/article/details/82937584
遇到的小bug
在使用netty进行websocket编程(实现一个简单的聊天室)时,我遇到了这样一个奇怪问题failed: Error during WebSocket handshake: Unexpected response code: 200。
google了一下发现还真有人也有这个错误。最后发现这是一个很低级的错误:
因为我之前写了一个websocket服务器端口还没释放,于是又写了一个新的websocket服务器同时运行,就出现了这个错误。
解决方法:关掉idea中所有运行的websocket端口,重新运行程序。
我的服务器端代码如下:
ChannelFuture future= server.bind(8080).sync()
js客户端代码:
//169.254.184.238是我用ipconfig Ping出来的本机ip地址
CHAT.socket =new WebSocket("ws://169.254.184.238:8080/ws");
然后一个简单的多人聊天室的小bug就解决了
聊天室后端代码:
package com.netty.websocket;
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;
/**
* netty服务器端启动类
* @author zgm
* @date 2018/10/4 12:08
*/
public class WSServer {
public static void main(String[] args) throws Exception{
EventLoopGroup mainGroup = new NioEventLoopGroup();
EventLoopGroup subGroup= new NioEventLoopGroup();
try {
ServerBootstrap server=new ServerBootstrap();
server.group(mainGroup,subGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new WSServerInitializer());
ChannelFuture future= server.bind(8080).sync();
future.channel().closeFuture().sync();
} finally {
mainGroup.shutdownGracefully();
subGroup.shutdownGracefully();
}
}
}
package com.netty.websocket;
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;
/**
* 通道初始化
* @author zgm
* @date 2018/10/4 12:12
*/
public class WSServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//websocket基于http协议,所以要有http编解码器
pipeline.addLast(new HttpServerCodec());
//对写大数据流的支持
pipeline.addLast(new ChunkedWriteHandler());
//对httpMessage进行聚合,聚合成FullHttpRequest或FullHttpResponse
//几乎在netty中的编程,都会使用到此handler
pipeline.addLast(new HttpObjectAggregator(1024 * 64));
// ======================以上用于支持http协议 ==================================
/**
* websocket 服务器处理的协议,用于指定给客户端访问的路由: /ws
* 本handler会帮你处理一些繁重复杂的事
* 会帮你处理握手动作 : handshaking (close, ping, pong) ping+pong=心跳
* 对于websocket来讲,都是以frames进行传输的,不同的数据类型对应frames不同
*/
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
//自定义的handler
pipeline.addLast(new ChatHandler());
}
}
package com.netty.websocket;
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;
import java.time.LocalDateTime;
/**
* 处理消息的handler
* TextWebSocketFrame: 在netty中,,是用于为websocket专门处理文本的对象,frame是消息的载体
*
* @author zgm
* @date 2018/10/4 12:26
*/
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
//用于记录和管理所有客户端的channel
private static ChannelGroup clients= new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
//获取客户端传输过来的消息
String content = textWebSocketFrame.text();
System.out.println("接受到的数据: " + content);
/* for(Channel channel : clients){
channel.writeAndFlush(new TextWebSocketFrame("【服务器在 " + LocalDateTime.now())+"接收到消息】 , 消息为: " + content);
}*/
//下面这条语句和上面的for循环一样效果
clients.writeAndFlush(new TextWebSocketFrame("【服务器在 " + LocalDateTime.now()+"接收到消息】 , 消息为: " + content));
}
/**
* 当客户端连接服务器端之后(打开连接)
* 获取客户端的channel,并放到ChannelGroup中去进行管理
* @param ctx
* @throws Exception
*/
@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().asLongText());
System.out.println("客户端断开,channel对应的短id为: "+ctx.channel().id().asShortText());
}
}
聊天室前端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>hello</title>
</head>
<body>
<div>发送消息</div>
<input type="text" id="msgContent" />
<input type="button" value="点我发送" onclick="CHAT.chat()" />
<div>接受消息</div>
<div id= "receiveMsg" style="background-color:orange;"></div>
<script type="application/javascript">
window.CHAT= {
socket: null,
init:function(){
if (window.WebSocket){
CHAT.socket =new WebSocket("ws://169.254.184.238:8080/ws");
CHAT.socket.onopen=function(){
console.log("连接建立成功");
},
CHAT.socket.onclose=function(){
console.log("连接关闭");
},
CHAT.socket.onerror=function(){
console.log("发生错误");
},
CHAT.socket.onmessage=function(e){
console.log("接受到消息:"+ e.data);
var receiveMsg= document.getElementById("receiveMsg");
var html = receiveMsg.innerHTML ;
receiveMsg.innerHTML=html+"<br/>"+e.data;
}
} else{
alert("浏览器不支持websocket协议。。。");
}
},
chat:function(){
var msg =document.getElementById("msgContent");
CHAT.socket.send(msg.value);
}
};
CHAT.init();
</script>
</body>
</html>
以上代码就实现了一个简单的聊天室。