一种轻量级websocket实现方案

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

一种轻量级websocket服务器和客户端实现方案

pom依赖

<dependency>
            <groupId>org.java-websocket</groupId>
            <artifactId>Java-WebSocket</artifactId>
            <version>1.5.3</version>
        </dependency>

服务器端案例

定义ws服务器工具类WsktUtil

package com.example.demo.util;

import cn.hutool.core.collection.ListUtil;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
public class WsktUtil extends WebSocketServer {


    private static List<WebSocket> clients = new CopyOnWriteArrayList<>();
    private static int port = 8843;


    private WsktUtil() {
        super(new InetSocketAddress(port));
    }

    private static final WsktUtil wskt = new WsktUtil();


    @Override
    public void onOpen(WebSocket conn, ClientHandshake handshake) {
        log.info("一个新客户端打开连接...");
        conn.send("Welcome to link wskt server!");


        //客户端ip
        String ip = conn.getRemoteSocketAddress().getAddress().getHostAddress();
        log.info("客户端请求的ip:{}", ip);
        int port = conn.getRemoteSocketAddress().getPort();
        log.info("客户端的port:{}", port);
        //客户端请求的 websocket path
        String resourceDescriptor = handshake.getResourceDescriptor();
        log.info("客户端请求的  path:{}", resourceDescriptor);
        clients.add(conn);


    }

    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {
        log.warn("一个客户端断开websocket连接...");
        String ip = conn.getRemoteSocketAddress().getAddress().getHostAddress();
        log.info("客户端请求的ip:{}", ip);
        int port = conn.getRemoteSocketAddress().getPort();
        log.info("客户端的port:{}", port);
        String resourceDescriptor = conn.getResourceDescriptor();
        log.info("客户端请求的 path:{}", resourceDescriptor);
        log.info("code:{}", code);
        log.info("reason:{}", reason);
        log.info("remote:{}", remote);
        clients.remove(conn);
    }

    @Override
    public void onMessage(WebSocket conn, String message) {
        log.info("一个客户端发送了消息....");
        String ip = conn.getRemoteSocketAddress().getAddress().getHostAddress();
        log.info("客户端请求的ip:{}", ip);
        int port = conn.getRemoteSocketAddress().getPort();
        log.info("客户端请求的port:{}", port);
        String resourceDescriptor = conn.getResourceDescriptor();
        log.info("客户端请求的path:{}", resourceDescriptor);
        log.info("客户端发送的msg:{}", message);

        handleClientReqMsg(conn, message);

    }

    @Override
    public void onError(WebSocket conn, Exception ex) {
        ex.printStackTrace();
        if (conn != null) {
            // some errors like port binding failed may not be assignable to a specific
            // websocket
            String ip = conn.getRemoteSocketAddress().getAddress().getHostAddress();
            log.info("异常客户端的ip:{}", ip);
            int port = conn.getRemoteSocketAddress().getPort();
            log.info("异常客户端的port:{}", port);
            String resourceDescriptor = conn.getResourceDescriptor();
            log.info("异常客户端的path:{}", resourceDescriptor);


        }
    }

    @Override
    public void onStart() {
        System.out.println("wskt Server started!");
        setConnectionLostTimeout(100); //连接丢失超时时间100s

        //启动后定时打印 客户端连接信息
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                printCurrentConns();
            }
        }, 1000, 3000); //延迟1s后,每3秒打印一次
    }

    private static void printCurrentConns() {
        int size = clients.size();
        log.info("--当前共有{}个websocket连接---", size);
        if (size > 0) {
            for (int i = 0; i < clients.size(); i++) {
                String ip = clients.get(i).getRemoteSocketAddress().getAddress().getHostAddress();
                int port = clients.get(i).getRemoteSocketAddress().getPort();
                String resourceDescriptor = clients.get(i).getResourceDescriptor();
                log.info("第{}个客户端的ip:{},port:{},path:{}", i + 1, ip, port, resourceDescriptor);
            }
        }
        log.info("--------------------------");
    }


    public static void startServer() throws UnknownHostException {
        wskt.start();
        log.info("wsktServer started on port: {}", wskt.getPort());
    }


    private static void handleClientReqMsg(WebSocket conn, String reqStr) {
        // 可以在这里处理req/resp形式的ws请求
        if (conn.getResourceDescriptor().equals("/123")) {
            if (reqStr.equals("aaa")) {
                publishMsgToClient("bbb", conn);
            }
        }
        if (conn.getResourceDescriptor().equals("/234")) {
            if (reqStr.equals("ccc")) {
                publishMsgToClient("ddd", conn);
            }
        }
    }


    public static void publishMsgToClient(String msg, WebSocket targetClient) {
        if (targetClient == null) {
            return;
        }
        String ip = targetClient.getRemoteSocketAddress().getAddress().getHostAddress();
        int port = targetClient.getRemoteSocketAddress().getPort();
        String resourceDescriptor = targetClient.getResourceDescriptor();
        wskt.broadcast(msg, ListUtil.toList(targetClient));
        log.info("server 发布消息:{}给客户端ip:{},port:{},path:{}", msg, ip, port, resourceDescriptor);
    }

    public static void publishMsgToSomeClients(String msg, Collection<WebSocket> clients) {
        if (clients == null || clients.size() == 0) {
            return;
        }
        wskt.broadcast(msg, clients);
        log.info("server 广播消息:{}", msg);
    }


    /**
     * ws://127.0.0.1:8843/123
     *
     * @param ip   127.0.0.1
     * @param port 8843
     * @param path /123
     * @return WebSocket
     */
    public static WebSocket getOneClient(String ip, int port, String path) {
        if (clients.size() > 0) {
            for (WebSocket client : clients) {
                if (client != null) {
                    int cPort = client.getRemoteSocketAddress().getPort();
                    String cip = client.getRemoteSocketAddress().getAddress().getHostAddress();
                    String cPath = client.getResourceDescriptor();
                    if (ip.equals(cip) && port == cPort && path.equals(cPath)) {
                        return client;
                    }
                }
            }
        }
        return null;
    }

    public static void serverPushClientTest(String msg) {
        if (clients.size() > 0) {
            for (WebSocket client : clients) {
                if (client != null) {
                    String ip = client.getRemoteSocketAddress().getAddress().getHostAddress();
                    int port = client.getRemoteSocketAddress().getPort();
                    String resourceDescriptor = client.getResourceDescriptor();

                    wskt.broadcast(msg, ListUtil.toList(client));
                    log.info("server 推送消息:{}给客户端ip:{},port:{},path:{}", msg, ip, port, resourceDescriptor);
                }
            }
        }
    }

}

开机启动ws服务器

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) throws UnknownHostException {
        SpringApplication.run(DemoApplication.class, args);

        WsktUtil.startServer();
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                WsktUtil.serverPushClientTest("server push:" + System.currentTimeMillis());
            }
        }, 6000, 5000);
    }

}

测试结果

2023-07-12 17:55:10.552  INFO 952 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8621 (http) with context path '/mybatis'
2023-07-12 17:55:10.563  INFO 952 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 3.046 seconds (JVM running for 3.791)
2023-07-12 17:55:10.569  INFO 952 --- [           main] com.example.demo.util.WsktUtil           : wsktServer started on port: 8843
wskt Server started!
2023-07-12 17:55:11.572  INFO 952 --- [        Timer-1] com.example.demo.util.WsktUtil           : --当前共有0个websocket连接---
2023-07-12 17:55:11.572  INFO 952 --- [        Timer-1] com.example.demo.util.WsktUtil           : --------------------------
2023-07-12 17:55:14.190  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 一个新客户端打开连接...
2023-07-12 17:55:14.193  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端请求的ip:127.0.0.1
2023-07-12 17:55:14.193  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端的port:58011
2023-07-12 17:55:14.193  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端请求的  path:/234
2023-07-12 17:55:14.195  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 一个客户端发送了消息....
2023-07-12 17:55:14.195  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端请求的ip:127.0.0.1
2023-07-12 17:55:14.195  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端请求的port:58011
2023-07-12 17:55:14.195  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端请求的path:/234
2023-07-12 17:55:14.195  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端发送的msg:
2023-07-12 17:55:14.572  INFO 952 --- [        Timer-1] com.example.demo.util.WsktUtil           : --当前共有1个websocket连接---
2023-07-12 17:55:14.572  INFO 952 --- [        Timer-1] com.example.demo.util.WsktUtil           : 第1个客户端的ip:127.0.0.1,port:58011,path:/234
2023-07-12 17:55:14.572  INFO 952 --- [        Timer-1] com.example.demo.util.WsktUtil           : --------------------------
2023-07-12 17:55:15.996  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 一个客户端发送了消息....
2023-07-12 17:55:15.996  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端请求的ip:127.0.0.1
2023-07-12 17:55:15.996  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端请求的port:58011
2023-07-12 17:55:15.997  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端请求的path:/234
2023-07-12 17:55:15.997  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : 客户端发送的msg:ccc
2023-07-12 17:55:15.999  INFO 952 --- [SocketWorker-43] com.example.demo.util.WsktUtil           : server 发布消息:ddd给客户端ip:127.0.0.1,port:58011,path:/234
2023-07-12 17:55:16.570  INFO 952 --- [        Timer-0] com.example.demo.util.WsktUtil           : server 推送消息:server push:1689155716570给客户端ip:127.0.0.1,port:58011,path:/234

客户端案例

自定义一个WebSocketClient子类

package cn.demo.wskt.client;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;

public class MyClient extends WebSocketClient {
    public MyClient(URI serverUri) {
        super(serverUri);
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        System.out.println("ws open");
        System.out.println(serverHandshake.getHttpStatus());
        System.out.println(serverHandshake.getHttpStatusMessage());
    }

    @Override
    public void onMessage(String s) {
        System.out.println("ws onMessage: "+s);
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        System.out.println("ws close");
        System.out.println("code: "+ code);
        System.out.println("reason: "+ reason);
        System.out.println("remote: "+ remote);
    }

    @Override
    public void onError(Exception ex) {
        ex.printStackTrace();
    }
}

测试连接ws服务器

package cn.demo.wskt.client;

import org.java_websocket.enums.ReadyState;

import java.net.URI;
import java.net.URISyntaxException;

public class MyClientTest {
    public static void main(String[] args) throws URISyntaxException, InterruptedException {
        MyClient client = new MyClient(new URI("ws://127.0.0.1:8843/123"));

        client.setConnectionLostTimeout(100);

        client.connect();

        while (!client.getReadyState().equals(ReadyState.OPEN)){
            System.out.println("wskt 连接中...");
            Thread.sleep(1000);
        }

        client.send("cli002-"+System.currentTimeMillis());

    }
}

测试效果

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
wskt 连接中...
ws open
101
Web Socket Protocol Handshake
ws onMessage: Welcome to link wskt server!
ws onMessage: server push:1689155751606
ws onMessage: server push:1689155756606
ws onMessage: server push:1689155761606
ws onMessage: server push:1689155766606

文章来源地址https://www.toymoban.com/news/detail-555310.html

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

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

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

相关文章

  • ETLCloud制造业轻量级数据中台解决方案

    制造业在业务发展过程中产生大量的业务交易数据以及设备运行过程中的状态数据,但是制造业有别于其他互联网或零售行业,其数据处理具有以下特点: 数据量不大,大部分业务系统的数据库表在1000W以下 数据结构复杂,数据需要经过很强的清洗和转换才能成为可用的分析

    2024年02月09日
    浏览(30)
  • Mainflux IoT:Go语言轻量级开源物联网平台,支持HTTP、MQTT、WebSocket、CoAP协议

    Mainflux是一个由法国的创业公司开发并维护的 安全、可扩展 的开源物联网平台,使用 Go语言开发、采用微服务的框架。Mainflux支持多种接入设备,包括设备、用户、APP;支持多种协议,包括HTTP、MQTT、WebSocket、CoAP,并支持他们之间的协议互转。 Mainflux的南向接口连接设备,北

    2024年02月01日
    浏览(90)
  • 英文论文(sci)解读复现【NO.21】一种基于空间坐标的轻量级目标检测器无人机航空图像的自注意

    此前出了目标检测算法改进专栏,但是对于应用于什么场景,需要什么改进方法对应与自己的应用场景有效果,并且多少改进点能发什么水平的文章,为解决大家的困惑,此系列文章旨在给大家解读发表高水平学术期刊中的 SCI论文 ,并对相应的SCI期刊进行介绍,帮助大家解

    2024年02月19日
    浏览(33)
  • 一种基于YOLO改进的高效且轻量级的表面缺陷检测网络, NEU-DET和GC10-DET涨点明显

    💡💡💡 本文摘要: 一种基于YOLO改进的高效且轻量级的表面缺陷检测, 在NEU-DET和GC10-DET任务中涨点明显 目录 1.轻量且高效的YOLO 1.1 SCRB介绍 1.1.1 ScConv介绍  1.2 GSConvns  1.3 od_mobilenetv2_050 1.4  对应yaml 2.实验结果 3.源码获取 轻量且高效的YOLO网络结构  其实ScConv和Bottleneck的基

    2024年01月19日
    浏览(24)
  • PikVM:轻量级虚拟化解决方案,让云计算更简单

    项目地址:https://gitcode.com/pikvm/pikvm PikVM 是一个创新的、轻量级的虚拟化平台,旨在简化云计算环境的部署和管理。它基于KVM(Kernel-based Virtual Machine),但提供了一种更加简洁且易于使用的接口,适合开发者、运维人员以及对虚拟化技术感兴趣的任何人。 PikVM 的核心理念是“

    2024年04月16日
    浏览(33)
  • 轻量级报表解决方案Telerik Reporting,轻松完成嵌入式报表交互!

    开发者可以通过多种方式与集成在应用程序中的Telerik报表进行交互,从“只是阅读它”到更改报表中包含的数据。 但是要注意:开发者所能做的一些事情将取决于报表是如何创建的,以及它是如何嵌入到应用程序UI中的。因此(和任何应用程序一样),为了从Telerik报表中获得想

    2024年02月08日
    浏览(42)
  • 【Github】自动监测 SSL 证书过期的轻量级监控方案 - Domain Admin

    在现代的企业网络中,网站安全和可靠性是至关重要的。一个不注意的SSL证书过期可能导致网站出现问题,给公司业务带来严重的影响。针对这个问题,手动检测每个域名和机器的证书状态需要花费大量的时间和精力。为了解决这个问题,我想向大家介绍一个自动监测SSL证书

    2024年02月15日
    浏览(25)
  • K3s vs K8s:轻量级对决 - 探索替代方案

    在当今云原生应用的领域中,Kubernetes(简称K8s)已经成为了无可争议的领导者。然而,随着应用规模的不断增长,一些开发者和运维人员开始感受到了K8s的重量级特性所带来的挑战。为了解决这一问题,一个名为K3s的新兴项目逐渐崭露头角。K3s被誉为轻量级的Kubernetes,它旨

    2024年02月14日
    浏览(28)
  • 轻量级软件FastGithub实现稳定访问github

    当我们想访问全球最大的“同性交友网站”https://github.com/ 时,总会出现无法访问的界面,令人非常苦恼: 幸运的是,有一种轻量级的软件可以帮助我们稳定地访问GitHub,那就是FastGithub。 FastGithub是一个简洁且专一的软件,它可以帮助你稳定地访问GitHub。FastGithub通过修改本地

    2024年02月06日
    浏览(35)
  • 使用es实现轻量级分布式锁

    一般来说,实现分布式锁的方式有哪几种? 一:Redisson实现 二:ZK实现   这两种实现网上的实现是千篇一律,在本文就不做过多的讲解了   其它方式好像没有了,真的是这样么?   答案是否定的,今天我就给大家分享一个新的思路,使用es实现一个分布式锁,分布式

    2024年02月06日
    浏览(42)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包