1.基本概念

首先websocket是基于H5的一种通信。在网页中如果定时获取服务器端的实时数据,我们常采用long poll 和ajax轮询的方式。但是在轮询过程中,由于根本没有新数据的改变,而造成一种资源的浪费,同时也不能够保证数据的实时性。long poll是一种保持长连接的方式获取数据,但是需要进行头文件的各种校验,也是一种资源的浪费。

websocket完美的解决了这种两种方式的不足,首先能够保证数据的实时性,同时保证资源的完整利用,是网页和服务端的全双工通信,即可以接收来自网页端的消息,同时可以发送通知网页端。websocket还支持多种方式,本篇讨论java,C#(WPF)和vue,即服务端为java,客户端分别为vue和WPF来进行验证。

2.基本原理

websocket是基于TCP的一种通信,所以在建立通信之前首先需要建立TCP的一系列连接(三次握手等)。

服务端采用Springboot来实现,首先在pom.xml中添加WebSocect的依赖

      <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

  接下来建立WebSocket并实现ServerEndPoint  我这里采用注解的方式

package com.koalin.rpc.websocket;

import com.utils.DateTimeUtils;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

/**
* @version 1.0
* @ClassName WebSocket
* @Author koalin
* @Description //TODO WebSocket的描述
* @Date 2019/12/24 23:27
*/
@ServerEndpoint("/koalin/websocket/{userName}")
@Component
public class WebSocket {
private Session session;
private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();

private static Map<String, Session> sessionPool = new HashMap<String, Session>();
volatile static boolean isRunning = false;
private String userName;

@OnOpen
public void onOpen(Session session, @PathParam(value = "userName") String userName) {
this.session = session;
this.userName = userName;
webSockets.add(this);
sessionPool.put(session.getId(), session);
System.out.println(userName + "【websocket消息】有新的连接,总数为:" + webSockets.size());

if (webSockets.size()==1) {
isRunning = true;
new Runnable() {
@Override
public void run() {
while (true) {
try {
for (WebSocket client :
webSockets) {
String msg = "Hello I am WebSocekt " + client.userName + "我的时间:" + DateTimeUtils.DateTimeYYYYMMDDHHMMSS(new Date());
client.session.getAsyncRemote().sendText(msg);
System.out.println(msg);

Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
isRunning=false;
}

}
}
}.run();
}
}

@OnClose
public void onClose() {
if (webSockets.contains(this) ){
webSockets.remove(this);
System.out.println(this.userName+"【websocket消息】连接断开,总数为:" + webSockets.size());
}

}

@OnMessage
public void onMessage(String message,Session session) {
//System.out.println("【websocket消息】收到客户端消息:" + message);
System.out.println("【websocket消息】收到客户端消息:" + message);
}

// 此为广播消息
public void sendAllMessage(String message) {
for (WebSocket webSocket : webSockets) {
System.out.println("【websocket消息】广播消息:" + message);
try {
webSocket.session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}

// 此为单点消息
public void sendOneMessage(String userName, String message) {
System.out.println("【websocket消息】单点消息:" + message);
Session session = sessionPool.get(userName);
if (session != null) {
try {
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}

}

添加WebSocketConfig 创建默认的EndPointServer

package com.koalin.rpc.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter; /**
* @version 1.0
* @ClassName WebSocketConfig
* @Author koalin
* @Description //TODO WebSocketConfig的描述
* @Date 2019/12/24 23:36
*/
@Configuration
public class WebSocketConfig { /**
* @return
* @Author koalin
* @Description //TODO这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
* @Date 22:47 2019/12/24
* @Param
**/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

以上完成服务端代码

接下来先验证C#客户端

首选在nuget中下载websocket-sharp

创建WebSocketClient

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WebSocketSharp; namespace WebSocketLib
{
public class WebSocketClient
{
private WebSocket ws;
private string url = "";
CancellationToken token = new CancellationToken();
public WebSocketClient(string url)
{ this.url = url;
} public void Start()
{ try
{
ws = new WebSocket(url, token, 102392,
() =>
{//OnOpen
return Task.Run(() =>
{
Console.WriteLine("websocket连接正常....");
});
},
(e) =>
{//OnClose
return Task.Run(() =>
{
Console.WriteLine("websocket关闭正常...");
});
},
(e) =>
{//OnMessage
return Task.Run(() =>
{
Console.WriteLine("接收到服务端的消息" + e.Text.ReadToEnd());
});
},
(e) =>
{//OnError
return Task.Run(() =>
{
Console.WriteLine("连接异常..." + e.Message);
});
}
); ws.Connect();
}
catch (Exception e)
{ Console.WriteLine(e.ToString());
}
}
 public void StartSendMessage()
        {

            Task.Run(async () =>
            {
                await Task.Delay(1000);
                while (true)
                {
                    try
                    {
                        if (ws != null ) 
                        {

                             Task<bool> tast= ws.Send(("HI i am C# client"+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));

                             Console.WriteLine(tast.Result);
                        }
                    }
                    catch (Exception ex)
                    {


                    }
                    await Task.Delay(2000);
                }
            });
        }
public void Close()
{
if (ws!=null)
{
ws.Close();
ws.Dispose();
}
}
}
}

简单的建立wpf窗体应用程序然后添加引用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes; namespace WebSocketDemo
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent(); }
WebSocketLib.WebSocketClient client = null;
private void Test()
{ client = new WebSocketLib.WebSocketClient("ws://www.koalin.com:8081/koalin/websocket/test"); client.Start(); client.StartSendMessage();
} private void Button_Click(object sender, RoutedEventArgs e)
{
Test();
} protected override void OnClosed(EventArgs e)
{
if (client!=null)
{
client.Close(); }
base.OnClosed(e);
}
}
}

  启动服务和客户端进行简单的验证

建立vue工程,然后添加如下websockt关键代码

initWebSocket () {

        // 连接错误
this.websocket.onerror = this.setErrorMessage
// 连接成功
this.websocket.onopen = this.setOnopenMessage
// 收到消息的回调
this.websocket.onmessage = this.setOnmessageMessage
// 连接关闭的回调
this.websocket.onclose = this.setOncloseMessage
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = this.onbeforeunload
},
setErrorMessage () {
console.log('WebSocket连接发生错误 状态码:' + this.websocket.readyState)
},
setOnopenMessage () {
console.log('WebSocket连接成功 状态码:' + this.websocket.readyState) },
setOnmessageMessage (event) {
// 根据服务器推送的消息做自己的业务处理
console.log('服务端返回:' + event.data)
},
setOncloseMessage () {
console.log('WebSocket连接关闭 状态码:' + this.websocket.readyState)
},
onbeforeunload () {
this.closeWebSocket()
}, closeWebSocket () {
this.websocket.close()
}
},
mounted() {
this.restaurants = this.loadAll();
// WebSocket
if ('WebSocket' in window) {
// var url='ws://www.koalin.com:8081/koalin/websocket/' + new Date();
this.websocket = new WebSocket('ws://www.koalin.com:8081/koalin/websocket/' + new Date());
console.log( this.websocket);
this.initWebSocket();
} else {
alert('当前浏览器 Not support websocket')
}
},
beforeDestroy () { this.onbeforeunload() }

启动vue服务。然后在网页中输入对应的链接。

完成简单的客户端与服务端的通信

浅析websocket的基本应用spring boot + vue +C# + WPF的更多相关文章

  1. spring boot+vue实现H5聊天室客服功能

    spring boot+vue实现H5聊天室客服功能 h5效果图 vue效果图 功能实现 spring boot + webSocket 实现 官方地址 https://docs.spring.io/ ...

  2. spring boot + vue + element-ui全栈开发入门——开篇

    最近经常看到很多java程序员朋友还在使用Spring 3.x,Spring MVC(struts),JSP.jQuery等这样传统技术.其实,我并不认为这些传统技术不好,而我想表达的是,技术的新旧程 ...

  3. spring boot + vue + element-ui全栈开发入门——基于Electron桌面应用开发

     前言 Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库. Electron通过将Chromium和Node.js合并到同一个运行时环 ...

  4. spring boot + vue + element-ui全栈开发入门

    今天想弄弄element-ui  然后就在网上找了个例子 感觉还是可以用的  第一步是完成了  果断 拿过来  放到我这里这  下面直接是连接  点进去 就可以用啊 本想着不用vue   直接导入连接 ...

  5. 一个实际的案例介绍Spring Boot + Vue 前后端分离

    介绍 最近在工作中做个新项目,后端选用Spring Boot,前端选用Vue技术.众所周知现在开发都是前后端分离,本文就将介绍一种前后端分离方式. 常规的开发方式 采用Spring Boot 开发项目 ...

  6. spring boot + vue + element-ui

    spring boot + vue + element-ui 一.页面 1.布局 假设,我们要开发一个会员列表的页面. 首先,添加vue页面文件“src\pages\Member.vue” 参照文档h ...

  7. 喜大普奔,两个开源的 Spring Boot + Vue 前后端分离项目可以在线体验了

    折腾了一周的域名备案昨天终于搞定了. 松哥第一时间想到赶紧把微人事和 V 部落部署上去,我知道很多小伙伴已经等不及了. 1. 也曾经上过线 其实这两个项目当时刚做好的时候,我就把它们部署到服务器上了, ...

  8. 部署spring boot + Vue遇到的坑(权限、刷新404、跨域、内存)

    部署spring boot + Vue遇到的坑(权限.刷新404.跨域.内存) 项目背景是采用前后端分离,前端使用vue,后端使用springboot. 工具 工欲善其事必先利其器,我们先找一个操作L ...

  9. 给大家整理了几个开源免费的 Spring Boot + Vue 学习资料

    最近抽空在整理前面的文章案例啥的,顺便把手上的几个 Spring Boot + Vue 的学习资料推荐给各位小伙伴.这些案例有知识点的讲解,也有项目实战,正在做这一块的小伙伴们可以收藏下. 案例学习 ...

随机推荐

  1. Hyperledger Fabric 智能合约开发及 fabric-sdk-go/fabric-gateway 使用示例

    前言 在上个实验 Hyperledger Fabric 多组织多排序节点部署在多个主机上 中,我们已经实现了多组织多排序节点部署在多个主机上,但到目前为止,我们所有的实验都只是研究了联盟链的网络配置方 ...

  2. CSS 网页字体最佳实践

    一般在网页的字体设置中,可以将字体分类三类: 系统字体:使用系统自带的字体 兜底字体:当系统字体无法正常使用,而兜底的字体 Emoji 字体:显示网页中的表情字体 为了满足不同平台,以及 Emoji ...

  3. 14.Nginx搭建及优化

    Nginx搭建及优化 目录 Nginx搭建及优化 Nginx服务基础 概述 Nginx和Apache的优缺点比较 编译安装Nginx服务 添加Nginx系统服务 Nginx服务配置文件 nginx服务 ...

  4. 六、LVM和从磁盘配额

    一.LVM概述 Logical Volume Manager,逻辑卷管理 优点:能够保证在现有数据不变的情况下,动态调整磁盘容量,从而提高磁盘管理的灵活性 /boot分区用于存放引导文件,不能基于LV ...

  5. go int64传到前端导致溢出问题排查

    简介 ​ 开周会的时候一位同事分享了一个踩坑经验,说在go里面还好好的int64类型,到前端就变得奇奇怪怪了,和原来不一样了.正好我对前端javascript有一点点了解,然后连夜写了点代码探索了一下 ...

  6. Servlet之Request和Response 解析

    原理 tomcat服务器会根据请求url中的资源路径,创建对应的Servlet的对象 tomcat服务器.会创建request和response对象,request对象中封装请求消息数据. tomca ...

  7. sql-DDL-操作数据库与表

    1. 操作数据库:CRUD oracle应该是没有操作数据库的SQL oracl创建数据库通过数据库提供的工具来新建数据库 windows版oracle新建数据库 C(Create):创建 creat ...

  8. SQL优化常用的几种方法

    为什么要对SQL优化: 1.执行性能低 2.等待时间过长 3.SQL写的太差 4.索引失效 ·····等等 SQL优化的一些方法: 1.EXPLAIN 做MySQL优化,我们要善用EXPLAIN查看S ...

  9. 深度学习基础-基于Numpy的多层前馈神经网络(FFN)的构建和反向传播训练

    本文是深度学习入门: 基于Python的实现.神经网络与深度学习(NNDL)以及花书的读书笔记.本文将以多分类任务为例,介绍多层的前馈神经网络(Feed Forward Networks,FFN)加上 ...

  10. 最著名的著名的比特币BTC钱包地址-中本聪的钱包

    最著名的著名的比特币BTC钱包地址-中本聪的钱包1.比特币创始人中本聪 1PTFYUG6nCzRrByoRfGT5kefUNuZjNF84o这个地址还是比特币的创世地址,比特币从未移动过,其中的50币 ...