Netty学习——通过websocket编程实现基于长连接的双攻的通信

Netty学习(一)基于长连接的双攻的通信,通过websocket编程实现



效果图,客户端和服务器端建立起长连接,客户端发送请求,服务器端响应

但是目前缺少心跳,如果两个建立起来的连接,一个断网之后,另外一个是感知不到对方已经断掉的。以后使用心跳技术来进行连接检测

须知:

状态码101,代表 协议转换,从HTTP协议升级为WebSocket协议

HTTP协议,一般访问的时候:是 Http://localhost:8080/ws

WebSocket协议,访问的时候,需要是:ws://localhost:8080/ws



实现代码:

服务器端:

package com.dawa.netty.fifthexample;

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;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.net.InetSocketAddress;

/**
 * @Title: MyServer
 * @Author: 大娃
 * @Date: 2019/11/28 14:02
 * @Description:
 */
public class MyServer {
    public static void main(String[] args)  throws Exception{
        //定义一个线程组 , 事件循环组 。 异步的NIO , 就是一个死循环。
        EventLoopGroup bossGroutp = new NioEventLoopGroup();  //不断的接受连接,但是不处理
        EventLoopGroup workerGroup = new NioEventLoopGroup(); // 完成后续处理,把结果返回给客户端
        try {

            //服务端,启动类
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //group方法,有两个参数的,有一个参数的
            serverBootstrap.group(bossGroutp, workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new WebSocketChannelInitializer()); //字处理器,自己 定义的

            ChannelFuture channelFuture = serverBootstrap.bind(new InetSocketAddress(8899)).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            //优雅关闭、
            bossGroutp.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
package com.dawa.netty.fifthexample;

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;

/**
 * @Title: WebSocketChannelInitializer
 * @Author: 大娃
 * @Date: 2019/11/28 14:06
 * @Description:
 */
public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new HttpServerCodec());
        pipeline.addLast(new ChunkedWriteHandler());//新的处理器   块
        pipeline.addLast(new HttpObjectAggregator(8192)); //将分开的段,给聚合到一起,形成完整的HTTP响应。很重要的一个对象,在处理HTTP的时候
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
        pipeline.addLast(new TextWebSocketFrameHandler());
    }
}
package com.dawa.netty.fifthexample;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.time.LocalDateTime;

/**
 * @Title: TextWebSocketFrameHandler
 * @Author: 大娃
 * @Date: 2019/12/2 08:33
 * @Description:
 */
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    /**
     *
     * @param ctx 上下文对象
     * @param msg //文本帧对象
     * @throws Exception 抛异常
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        System.out.println("收到消息:"+msg.text());
        ctx.channel().writeAndFlush(new TextWebSocketFrame("服务器时间:"+ LocalDateTime.now() )); //不能直接传入 字符串.因为不同协议的规范不同,websocket要求要传回这种的对象
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("handlerAdded:" + ctx.channel().id().asLongText());//每一个channel 都有一个唯一的id值与其对应
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("HandlerRemoved:" + ctx.channel().id().asLongText());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.channel().close();
    }
}

客户端(使用HTML,JS来代替模拟客户端)

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>websocket客户端</title>
 6 </head>
 7 <body>
 8 <!--
 9
10 -->
11 <script type="text/javascript">
12     //使用浏览器,进行websocket服务器端的访问
13     var socket;
14     if (window.WebSocket) {//判断浏览器是否支持websocket
15         socket = new WebSocket("ws:localhost:8899/ws"); //建立websocket连接
16         socket.onmessage = function (ev) { //如果socket收到消息,这个onmessage方法就会被回调
17             var ta = document.getElementById(‘responseText‘);
18             ta.value = ta.value + "\n" + ev.data;
19         };
20
21         socket.onopen=function (ev) {//当连接被打开的时候,执行的回调
22             var ta = document.getElementById(‘responseText‘);
23             ta.value = "连接开启!";
24         };
25
26         socket.onclose = function (ev) {
27             var ta = document.getElementById(‘responseText‘);
28             ta.value = ta.value + "\n" + "连接断开!";
29         };
30     } else {
31         alert("浏览器不支持Websocket")
32     }
33
34     function send(message) {
35         if (!window.WebSocket) {
36             return;
37         }
38         if (socket.readyState === WebSocket.OPEN) {
39             socket.send(message);
40         } else {
41             alert("连接未开启");
42         }
43     }
44 </script>
45
46 <!--客户端访问后台 websocket程序-->
47 <form action="" onsubmit="return false;">
48     <textarea name="message" style="width: 400px;height: 200px;"></textarea>
49
50     <input type="button" value="发送数据" onclick="send(this.form.message.value)">
51
52     <h3>服务器端输出:</h3>
53     <textarea id="responseText" style="width: 400px;height: 300px;"></textarea>
54     <input type="button" onclick="javascript:document.getElementById(‘responseText‘).value=‘‘;" value="清空内容">
55 </form>
56 </body>
57 </html>

原文地址:https://www.cnblogs.com/bigbaby/p/11969625.html

时间: 2024-10-06 17:31:27

Netty学习——通过websocket编程实现基于长连接的双攻的通信的相关文章

Python网络编程02/基于TCP协议的socket简单的通信

目录 Python网络编程02/基于TCP协议的socket简单的通信 1.昨日内容回顾 2.socket 2.1 socket套接字 2.2 基于TCP协议的socket简单通信 Python网络编程02/基于TCP协议的socket简单的通信 1.昨日内容回顾 1.单播:单独联系某一个人 2.广播:给所有人发送消息(群发) 3.比特流:bit就是0101跟水流一样的源源不断的发送01010101 4.以太网协议:将数据进行分组:一组称之为一帧,数据报 head|data head:18字节:

基于长连接简单聊天

一.由来 最近,公司需要一个即时聊天功能.为此,曾尝试SignalR,Tencent Mars,重点研究了下mars项目,该项目支持Android,iOS端通信,并能对网络进行优化处理,是微信内部运行架构.服务端是基于Netty框架通信,数据通过protobuf封装,并自定义了一套通信协议.客户端通信,通过封装好的类库进行调用.因此,对于项目较急的,上线快速,此方案研究耗时较长,不满足现状.因此,在此先试用简单长连接,并设置好接口,以备后续直接切换成成熟框架. 作为研究学习记录,对简单长连接做一

通过netty实现服务端与客户端的长连接通讯,及心跳检测。

基本思路:netty服务端通过一个Map保存所有连接上来的客户端SocketChannel,客户端的Id作为Map的key.每次服务器端如果要向某个客户端发送消息,只需根据ClientId取出对应的SocketChannel,往里面写入message即可.心跳检测通过IdleEvent 事件,定时向服务端放送Ping消息,检测SocketChannel是否终断. 环境JDK1.8 和netty5 以下是具体的代码实现和介绍: 1公共的Share部分(主要包含消息协议类型的定义) 设计消息类型:

学习笔记——网络编程3(基于TCP协议的网络编程)

TCP协议基础 IP协议是Internet上使用的一个关键协议,它的全称是Internet Protocol,即Internet协议,通常简称IP协议. 使用ServerSocket创建TCP服务器 在两个通信实体没有建立虚拟链路之前,必须有一个通信实体先做出“主动姿态”,主动接收来自其他通信实体的连接请求. Java中能接收其他通信实体连接请求的类是ServerSocket,ServerSocket对象用于监听来自客户端Socket连接,如果没有连接,它将一直处于等待状态. ServerSoc

Netty实现服务端客户端长连接通讯及心跳检测

通过netty实现服务端与客户端的长连接通讯,及心跳检测.        基本思路:netty服务端通过一个Map保存所有连接上来的客户端SocketChannel,客户端的Id作为Map的key.每次服务器端如果要向某个客户端发送消息,只需根据ClientId取出对应的SocketChannel,往里面写入message即可.心跳检测通过IdleEvent 事件,定时向服务端放送Ping消息,检测SocketChannel是否终断.         环境JDK1.8 和netty5      

HTTP的长连接和短连接——Node上的测试

    本文主要从实践角度介绍长.短连接在TCP层面的表现,借助Node.JS搭建后台服务,使用WinHTTP.Ajax做客户端请求测试,最后简单涉及WebSocket.     关键字:长连接.短连接.Node.JS.WebSocket. 一两年前,在理论上对长短连接做了学习,那时的技能以客户端为主,所以也止步于客户端和网络抓包,两年来后台技术渐有把握,打算从前到后的实践一遍.如对理论有不理解的,可以先google/百度 一下,或者看看这篇偏理论的介绍:HTTP的长连接和短连接. 1 短连接的

HTTP 长连接 使用场景

offer 80 非常多应用譬如监控.即时通信.即时报价系统都须要将后台发生的变化实时传送到client而无须client不停地刷新.发送请求. 在 多好科技的那位技术指导问我这个是由于他们做物连网,监控,使用长连接多. Comet:基于 HTTP 长连接的"server推"技术 HTML5后 .WebSocket替代 Comet实现 长连接:WebSocket的维基 从WebSocket看到Jetty :  Jetty(Web Server) Google 选择 Jetty 放弃to

互联网推送服务原理:长连接+心跳机制(MQTT协议)

互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了,所以才会出现像MQTT这种轻量级低消耗的协议来维护长连接,那么要如何维护长连接呢: 在写之前,我们首先了解一下为什么Android维护长连接需要心跳机制,首先我们知道,维护任何一个长连接都需要心跳机制,客户端发送一个心跳给 服务器,服务器给客户端一个心跳应答,这样就形成客户端服务器的一次完整的握手

移动互联网消息推送原理:长连接+心跳机制(MQTT协议)

互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了,所以才会出现像MQTT这种轻量级低消耗的协议来维护长连接,那么要如何维护长连接呢: 在写之前,我们首先了解一下为什么Android维护长连接需要心跳机制,首先我们知道,维护任何一个长连接都需要心跳机制,客户端发送一个心跳给 服务器,服务器给客户端一个心跳应答,这样就形成客户端服务器的一次完整的握手