websocket实现通讯——Java

这篇具有很好参考价值的文章主要介绍了websocket实现通讯——Java。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


参考博客0

一、webSocket的作用

1)通知功能:
2)数据收集:
3)加密 && 认证:
4)反向控制钩子:

二、webSocket的优缺点

1、优点

1、websocket则允许我们在一条ws连接上同时并发多个请求,即在A请求发出后A响应还未到达,就可以继续发出B请求。由于TCP的慢启动特性(新连接速度上来是需要时间的),以及连接本身的握手损耗,都使得websocket协议的这一特性有很大的效率提升。
2、webSocket的复用性可以利用上一条请求内容
3、websocket支持服务器推送消息,这带来了及时消息通知的更好体验,也是ajax请求无法达到的。

2、缺点

1、服务器长期维护长连接需要一定的成本
2、各个浏览器支持程度不一
3、websocket 是长连接,受网络限制比较大,需要处理好重连,比如用户进电梯或电信用户打个电话网断了,这时候就需要重连

3、webSocket与Http协议的异同

参考博客

三、webSocket重要步骤

步骤:
	1.后端
		a.搭建服务器和处理器
	2.前端
		a.判断是否支持webSocket
		b.创建webSocket对象设置参数uri
		c.设计发送(send)、接收和显示(show)消息方法
		d.心跳机制:确保客户端或服务器活着
		e.重连机制:当客户端或服务器恢复后能够重新连上

1、后端

1.1、webSocket服务器搭建

  • 导入依赖
		<dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.77.Final</version>
        </dependency>
  • 服务类代码实现
package com.wxl.websocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;

public class WebSocketServer {
    public static void main(String[] args) {
        try {
            EventLoopGroup master = new NioEventLoopGroup();
            EventLoopGroup salve=new NioEventLoopGroup();

            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(master,salve);
            bootstrap.channel(NioServerSocketChannel.class);
            bootstrap.childHandler(new ChannelInitializer() {
                @Override
                protected void initChannel(Channel channel) throws Exception {
                    ChannelPipeline pipeline = channel.pipeline();
                    //http编码器
                    pipeline.addLast(new HttpServerCodec());
                    pipeline.addLast(new HttpObjectAggregator(1024*10));

                    pipeline.addLast(new WebSocketServerProtocolHandler("/"));//此处设置映射路径
                    //自定义客户端处理器
                    pipeline.addLast(new WebSocketServerHandler());
                }
            });
            ChannelFuture channelFuture = bootstrap.bind(8081);
            channelFuture.sync();
            System.out.println("服务端启动成功。。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

注意:在添加处理器的位置添加客户端超过多久未发送信息便自动断开连接的处理器——//客户端10s不发送信息自动断开
pipeline.addLast(new ReadTimeoutHandler(10, TimeUnit.SECONDS));

  • 自定义处理类代码实现
package com.wxl.websocket;

import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.EventExecutorGroup;

public class WebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        System.out.println("读取客户端的内容:"+textWebSocketFrame.text());
        String text=textWebSocketFrame.text();
        if (text.equals("heard")){//处理心跳
            //响应heard到客户端
            TextWebSocketFrame heard = new TextWebSocketFrame("heard");
            channelHandlerContext.writeAndFlush(heard);
            return;
        }
        TextWebSocketFrame textWebSocketFrame1 = new TextWebSocketFrame("嗯");
        channelHandlerContext.writeAndFlush(textWebSocketFrame1);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("新客户端建立连接。。。。");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端断开连接。。。。");
    }
}

2、前端

1.1、心跳机制

  1. 心跳代码
			//心跳机制
			sendHeard(){
				//每5秒发送一次
				this.sendHeardTime=setInterval(function() {
					//向服务端发送消息
					ws.send("heard");
				}, 5000);
			},

注意:在data方法中定义sendHeardTime:undefined==》用于后序clearInterval(sendHeardTime)清除该定时事件

  1. 超时关闭连接的方法
  • 当客户端发送心跳后多久后未收到服务端回的心跳,便断开连接。
  • 实现代码
			//关闭连接
			closeConn(){
				this.closeConnTime=setTimeout(function(){
					ws.close();
				},10000);
			},
  1. 在onopen方法中调用——两方法
  2. 在onmessage方法中收到服务端回的心跳后,调用clearTimeout,并再次调closeConn方法
  3. 在onclose和destroyed方法中clearInterval

1.2、重连机制

  1. 重连的代码
			//重连机制
			reConn(){
				console.info("重连");
				setTimeout(()=>{
					this.initWebSocket();
				},5000);
			}
  1. 在onclose方法中调用

四、通讯项目思想

java发送websocket请求,java,websocket,网络

1、服务搭建

服务划分:
	1、搭建eureka注册中心
	2、config服务,将所有配置集中放到该服务
	3、用户服务——处理各种业务逻辑
	4、网关服务
	5、netty服务——通讯

2、创建多个实体类处理不同业务

java发送websocket请求,java,websocket,网络

同时创建各自的处理类,将处理类添加到websocket服务类

实体类:

  • ConnMsg实体类
    java发送websocket请求,java,websocket,网络

  • NettyMsg
    java发送websocket请求,java,websocket,网络

  • ShutDownMsg
    java发送websocket请求,java,websocket,网络

  • ChannelGroup实体类

package com.wxl;

import io.netty.channel.Channel;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 保存所有的客户端的连接  设备id,channel
 */
public class ChannelGroup {
    /**
     * key:设备id
     * channel:设备id的连接对象
     */
    public static Map<String, Channel> channelMap=new HashMap<>();

    /**
     * 添加channel到容器中
     * @param did
     * @param channel
     */
    public static void addChannel(String did,Channel channel){
        channelMap.put(did,channel);
    }

    /**
     * 获取channel对象
     * @param did
     * @return
     */
    public static Channel getChannel(String did){
        return channelMap.get(did);
    }

    /**
     * 删除channel对象
     * @param did
     */
    public static void removeChannel(String did){
        channelMap.remove(did);
    }

    public static void removeChannel(Channel channel){
        if (channelMap.containsKey(channel)){
            Set<Map.Entry<String, Channel>> entries = channelMap.entrySet();
            for (Map.Entry<String, Channel> entry : entries) {
                if (entry.getValue()==channel){
                    channelMap.remove(entry.getKey());
                    break;
                }
            }
        }
    }

}
		
  • websocket的主处理类webSocketHandler,先执行该处理类再处理其他处理类
    java发送websocket请求,java,websocket,网络

3、实现用户挤下线的功能

主要步骤
	1、引入redis存储用户id和设备id
	2、引入rabbitmq,通过交换机和队列,来实现用户服务查询websocket服务中注册的channel
	3、创建ChannelGroup实体类,并定义一个map属性来存储设备id和channel

1、redis

  1. 引入依赖和添加配置
  2. 在用户服务注入StringRedisTemplate——存入redis的数据对为(用户id:设备id)
  3. 在login业务中——根据用户id查询设备id
  4. 判断设备id与前端传来的是否相等,不等创建shutDownMsg对象,rabbitmq发送消息
    java发送websocket请求,java,websocket,网络
  5. 挤下操作

    1、目的:根据设备id获取对应的channel

2、rabbitmq

  1. 用户端和netty服务端引入依赖,添加配置

  2. 用户端注入Rabbitmq,主要负责给交换机发送数据
    java发送websocket请求,java,websocket,网络

  3. 创建队列和交换机,同时绑定队列和交换机
    java发送websocket请求,java,websocket,网络

  4. 创建监听类——监听是否向交换机发送了消息
    java发送websocket请求,java,websocket,网络

  5. 前端获取服务端消息onmassege()——方法查询html5plus官网
    java发送websocket请求,java,websocket,网络

  6. 在客户端断开连接后需在主webSocketHandler处理器的unregistered方法中将当前channel从ChannelGroup中删除
    java发送websocket请求,java,websocket,网络

  7. 在ConnMsgHandler类(客户端连接处理器)中使用构造器的方法将websocket主服务类中注入的redisTemplate通过参数传入该类
    java发送websocket请求,java,websocket,网络文章来源地址https://www.toymoban.com/news/detail-554418.html

五、整体代码

1.vue

<template>
	<view>
		<view style="width: 400px;height: 300px;border: 1px solid red;" id="showMgs">
			<!-- <view v-for="(item,index) in msgs" :key="index" v-html="item.cnt"></view> -->
		</view>
		<view style="border: 1px solid red;width: 400px;">
			<input style="float: left;border: 1px solid green; width: 200px;height: 40px;" type="text" v-model="cnt"/>
			<button style="width: 100px;height: 40px;line-height: 40px;" @click="sendMsg">发送</button>
		</view>
		
		
	</view>
</template>

<script>
	import $ from 'jquery';
	var ws;
	export default {
		data() {
			return {
				cnt:'',
				flage:true,
				closeConnTime:undefined,	//超过多少时间关闭连接的事件
				sendHeardTime:undefined,	//定时发送心跳机制
			}
		},
		
		created() {
			this.initWebSocket();
		},
		destroyed() {
			clearInterval(this.sendHeardTime);
			ws.close();
			//this.reConn();//重连
		},
		methods: {
			initWebSocket(){
				console.log("1");
				//是否支持websocket属性
				if(window.WebSocket){
					console.log("2");
					//连接服务器
					ws=new WebSocket("ws://localhost:8081/");
					ws.onmessage = this.websocketonmessage;
					ws.onopen = this.websocketonopen;
					ws.onerror = this.websocketonerror;
					ws.onclose = this.websocketclose;
				}else{
					alert("不支持websocket服务器");
				}
			},
			//客户端接收服务端数据时触发
			websocketonmessage(data){
				if(data.data!="heard"){
					console.info("客户端响应数据"+data.data);
					$("#showMgs").append("<span>我:"+data.data+"</span><br>");						
				}else{
					clearTimeout(this.closeConnTime);//清除定时关闭的连接
					this.closeConn();
					console.info("心跳:"+data.data);
				}
				//this.msgs.push("<span>我:"+data.data+"</span><br>");
			},
			websocketonopen(){//连接建立时触发
				console.info("客户端连接成功。。。。");
				$("#showMgs").append("<span style='color:green;'>客户端连接成功</span><br>");
				//this.msgs.push({cnt:"<span style='color:green;'>客户端连接成功</span><br>"});
				//成功连接之后调用心跳
				this.sendHeard();
				this.closeConn();
			},
			//通信发生错误时触发
			websocketonerror(){
				console.info("通信发生错误。。。");
			},
			websocketclose(){//连接关闭时触发
				clearInterval(this.sendHeardTime);//清除定时发送心跳事件
				this.reConn();//重连
				console.info("客户端断开连接。。。");
				$("#showMgs").append("<span style='color:red;'>客户端断开连接</span><br>");
				//this.msgs.push("<span style='color:red;'>客户端断开连接</span><br>");
			},
			sendMsg(){
				//var msg=$("#cnt").val();
				var msg=this.cnt;
				console.info(msg);
				//发送消息
				ws.send(msg);//将数据发送到webSocket服务端
				//将数据显示到页面
				$("#showMgs").append("<span>我:"+msg+"</span><br>");
				//this.msgs.push("<span>我:"+msg+"</span><br>");
			},
			
			//心跳机制
			sendHeard(){
				//每5秒发送一次
				this.sendHeardTime=setInterval(function() {
					//向服务端发送消息
					ws.send("heard");
				}, 5000);
			},
			//关闭连接
			closeConn(){
				this.closeConnTime=setTimeout(function(){
					ws.close();
				},10000);
			},
			//重连机制
			reConn(){
				console.info("重连");
				setTimeout(()=>{
					this.initWebSocket();
				},5000);
			}
			
		}
	}
</script>

<style>

</style>

到了这里,关于websocket实现通讯——Java的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • jmeter使用之发送webSocket请求

    在工作中,我们经常需要进行接口测试,最近做了一个项目用的是websockert协议,接口测试使用jmeter进行。以下是我用jmeter发送twebSocket协议的操作步骤。 一、jmeter下载 访问jmeter官网 https://jmeter.apache.org/,点击左侧的“Download Releases”链接 下载所需版本的jmeter,我使用的是5.

    2024年04月17日
    浏览(35)
  • JAVA使用WebSocket实现多客户端请求

    工作前提:两个服务之间实现聊天通讯,因为介于两个服务,两个客户端 方案1:多个服务端,多个客户端,使用redis把用户数据ip进行存储,交互拿到redis数据进行推送 方案2: 一个服务端,多个客户端,拿到客户端的id和需要推送的id进行拼接存储 此文章使用的是方案2 1. 引

    2024年02月11日
    浏览(48)
  • java后端使用websocket实现与客户端之间接收及发送消息

    客户端请求websocket接口,连接通道=》我这边业务成功客户端发消息=》客户端自动刷新。 接口:ws://localhost:8080/websocket/xx 经测试,成功 如果是线上服务器连接,则需要在nginx里配置websocket相关内容,再重启nginx,代码如下 本地连接的时候用的是ws://,因为是http链接,但是如果是

    2024年02月16日
    浏览(46)
  • java发送form-data请求实现文件上传

    需要请求第三方接口上传文件,该请求类型是form-data请求   注意: 这里的 builder.addPart(\\\"sendfile\\\", new FileBody(file)); , multipartFile 对应form表单的字段名称。 参考:Java发送form-data请求实现文件上传_IceFloe_Rot的博客-CSDN博客

    2024年01月18日
    浏览(63)
  • Python向带有SSL/TSL认证服务器发送网络请求小实践(附并发http请求实现asyncio+aiohttp)

    最近工作中遇到这样的一个场景:给客户发送文件的时候,为保证整个过程中,文件不会被篡改,需要在发送文件之间, 对发送的文件进行签名, 而整个签名系统是另外一个团队做的, 提供了一个接口服务完成签名,但访问这个接口需要提供他们团队提供的证书链先进行认

    2024年04月16日
    浏览(45)
  • 用java实现模仿 Postman 发送 form-data 形式的请求,并指定编码格式

    可以使用 Apache HttpClient 库来模仿 Postman 发送 form-data 形式的请求,并指定编码格式。以下是一个示例代码: 在这个示例中, YOUR_ENDPOINT_URL 应该被替换为目标 URL。这段代码使用了 Apache HttpClient 库创建了一个带有 form-data 的请求,并使用 UrlEncodedFormEntity 设置了编码格式为 UTF-

    2024年02月02日
    浏览(56)
  • Java Websocket发送文件给Vue客户端接收并上传,实现检测U盘插入并将指定文件上传到服务器功能

    应用环境: B/S架构 需求描述: 1、判断U盘接入 2、扫描U盘指定文件,将满足条件的文件发送给服务器 解决思路: 1、因为bs架构,无法获取本机资源,计划在U盘所在服务器部署websocket服务 2、websocket服务扫描u盘,拿到指定文件,使用session.getBasicRemote().sendBinary(data)分批发送二

    2024年01月15日
    浏览(56)
  • Netty 教程 – 实现WebSocket通讯

    WebSocket 协议是基于 TCP 的一种新的网络协议,它实现了浏览器与服务器 全双工(full-duplex)通信 ,允许 服务器主动发送信息给客户端 优点及作用 Http协议的弊端: Http协议为半双工协议。(半双工:同一时刻,数据只能在客户端和服务端一个方向上传输) Http协议冗长且繁琐 易

    2024年02月09日
    浏览(36)
  • SpringBoot+WebSocket实现即时通讯(四)

    紧接着上文《SpringBoot+WebSocket实现即时通讯(三)》 本博客姊妹篇 SpringBoot+WebSocket实现即时通讯(一) SpringBoot+WebSocket实现即时通讯(二) SpringBoot+WebSocket实现即时通讯(三) SpringBoot+WebSocket实现即时通讯(四) 用户管理:业务自己实现,暂从数据库添加 好友管理:添加好

    2024年02月21日
    浏览(43)
  • uniapp使用WebSocket实现即时通讯

    UniApp是一个基于Vue.js的跨平台应用开发框架,它允许开发者使用HTML、CSS和JavaScript构建多平台的移动应用程序。要使用WebSocket在UniApp中实现即时通讯功能,你可以按照以下步骤进行操作: 在UniApp项目的根目录下,找到 manifest.json 文件并打开它。 在 manifest.json 文件中,添加以下

    2024年02月06日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包