使用netty實現一個多人聊天室--failed: Error during WebSocket handshake: Unexpected response code: 200

初次接觸netty , 本文主要內容如下:

遇到的小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>

以上代碼就實現了一個簡單的聊天室。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章