SpringBoot2+Netty+WebSocket(netty實現websocket,支持URL參數)

關於Netty
Netty 是一個利用 Java 的高級網絡的能力,隱藏其背後的複雜性而提供一個易於使用的 API 的客戶端/服務器框架。

更新
2019-7-11 新增URL參數支持,並解決了帶參URL導致的連接自動斷開問題,感謝大家的支持。
MAVEN依賴
    <dependencies>
        <!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.36.Final</version>
        </dependency>

    </dependencies>
1
2
3
4
5
6
7
8
9
SpringBootApplication
啓動器中需要new一個NettyServer,並顯式調用啓動netty。

@SpringBootApplication
public class SpringCloudStudyDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudStudyDemoApplication.class,args);
        try {
            new NettyServer(12345).start();
            System.out.println("https://blog.csdn.net/moshowgame");
            System.out.println("http://127.0.0.1:6688/netty-websocket/index");
        }catch(Exception e) {
            System.out.println("NettyServerError:"+e.getMessage());
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
NettyServer
啓動的NettyServer,這裏進行配置

/**
 * NettyServer Netty服務器配置
 * @author zhengkai.blog.csdn.net
 * @date 2019-06-12
 */
public class NettyServer {
    private final int port;
 
    public NettyServer(int port) {
        this.port = port;
    }
 
    public void start() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
 
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            ServerBootstrap sb = new ServerBootstrap();
            sb.option(ChannelOption.SO_BACKLOG, 1024);
            sb.group(group, bossGroup) // 綁定線程池
                    .channel(NioServerSocketChannel.class) // 指定使用的channel
                    .localAddress(this.port)// 綁定監聽端口
                    .childHandler(new ChannelInitializer<SocketChannel>() { // 綁定客戶端連接時候觸發操作
 
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("收到新連接");
                            //websocket協議本身是基於http協議的,所以這邊也要使用http解編碼器
                            ch.pipeline().addLast(new HttpServerCodec());
                            //以塊的方式來寫的處理器
                            ch.pipeline().addLast(new ChunkedWriteHandler());
                            ch.pipeline().addLast(new HttpObjectAggregator(8192));
                            ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", null, true, 65536 * 10));
                            ch.pipeline().addLast(new MyWebSocketHandler());
                        }
                    });
            ChannelFuture cf = sb.bind().sync(); // 服務器異步創建綁定
            System.out.println(NettyServer.class + " 啓動正在監聽: " + cf.channel().localAddress());
            cf.channel().closeFuture().sync(); // 關閉服務器通道
        } finally {
            group.shutdownGracefully().sync(); // 釋放線程池資源
            bossGroup.shutdownGracefully().sync();
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
MyChannelHandlerPool
通道組池,管理所有websocket連接

/**
 * MyChannelHandlerPool
 * 通道組池,管理所有websocket連接
 * @author zhengkai.blog.csdn.net
 * @date 2019-06-12
 */
public class MyChannelHandlerPool {

    public MyChannelHandlerPool(){}

    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
MyWebSocketHandler
處理ws一下幾種情況:

channelActive與客戶端建立連接
channelInactive與客戶端斷開連接
channelRead0客戶端發送消息處理
/**
 * NettyServer Netty服務器配置
 * @author zhengkai.blog.csdn.net
 * @date 2019-06-12
 */
public class NettyServer {
    private final int port;
 
    public NettyServer(int port) {
        this.port = port;
    }
 
    public void start() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
 
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            ServerBootstrap sb = new ServerBootstrap();
            sb.option(ChannelOption.SO_BACKLOG, 1024);
            sb.group(group, bossGroup) // 綁定線程池
                    .channel(NioServerSocketChannel.class) // 指定使用的channel
                    .localAddress(this.port)// 綁定監聽端口
                    .childHandler(new ChannelInitializer<SocketChannel>() { // 綁定客戶端連接時候觸發操作
 
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("收到新連接");
                            //websocket協議本身是基於http協議的,所以這邊也要使用http解編碼器
                            ch.pipeline().addLast(new HttpServerCodec());
                            //以塊的方式來寫的處理器
                            ch.pipeline().addLast(new ChunkedWriteHandler());
                            ch.pipeline().addLast(new HttpObjectAggregator(8192));
                            ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", "WebSocket", true, 65536 * 10));
                            ch.pipeline().addLast(new MyWebSocketHandler());
                        }
                    });
            ChannelFuture cf = sb.bind().sync(); // 服務器異步創建綁定
            System.out.println(NettyServer.class + " 啓動正在監聽: " + cf.channel().localAddress());
            cf.channel().closeFuture().sync(); // 關閉服務器通道
        } finally {
            group.shutdownGracefully().sync(); // 釋放線程池資源
            bossGroup.shutdownGracefully().sync();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
socket.html
主要是連接ws,發送消息,以及消息反饋

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Netty-Websocket</title>
    <script type="text/javascript">
        // by zhengkai.blog.csdn.net
        var socket;
        if(!window.WebSocket){
            window.WebSocket = window.MozWebSocket;
        }
        if(window.WebSocket){
            socket = new WebSocket("ws://127.0.0.1:12345/ws");
            socket.onmessage = function(event){
                var ta = document.getElementById('responseText');
                ta.value += event.data+"\r\n";
            };
            socket.onopen = function(event){
                var ta = document.getElementById('responseText');
                ta.value = "Netty-WebSocket服務器。。。。。。連接  \r\n";
            };
            socket.onclose = function(event){
                var ta = document.getElementById('responseText');
                ta.value = "Netty-WebSocket服務器。。。。。。關閉 \r\n";
            };
        }else{
            alert("您的瀏覽器不支持WebSocket協議!");
        }
        function send(message){
            if(!window.WebSocket){return;}
            if(socket.readyState == WebSocket.OPEN){
                socket.send(message);
            }else{
                alert("WebSocket 連接沒有建立成功!");
            }
 
        }
 
    </script>
</head>
<body>
<form onSubmit="return false;">
    <label>ID</label><input type="text" name="uid" value="${uid!!}" /> <br />
    <label>TEXT</label><input type="text" name="message" value="這裏輸入消息" /> <br />
    <br /> <input type="button" value="發送ws消息"
                  onClick="send(this.form.uid.value+':'+this.form.message.value)" />
    <hr color="black" />
    <h3>服務端返回的應答消息</h3>
    <textarea id="responseText" style="width: 1024px;height: 300px;"></textarea>
</form>
</body>
</html>

 

 

 

文章標籤: springboot websocket springboot netty websocket ttnerry websocket netty實現websocket
版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://zhengkai.blog.csdn.net/article/details/91552993
————————————————
版權聲明:本文爲CSDN博主「Moshow鄭鍇」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://zhengkai.blog.csdn.net/article/details/91552993

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