导航

  • Socket.IO是什么
  • Socket.IO的应用场景
  • 为什么选socket.io-client-java
  • 实战案例
  • 参考

本文首发于智客工坊-《socket.io客户端向webserver发送消息实践》,感谢您的阅读,预计阅读时长2min。

Socket.IO是什么

Socket.IO是一个库,它支持客户端和服务器之间的低延迟双向基于事件的通信。

它构建在WebSocket协议之上,并提供额外的保证,如回退到HTTP长轮询或自动重新连接。


Socket.IO的应用场景

Socket.IO目前应用比较多的场景就是网页的IM实时聊天。

Notes: 在C#中,也有个类库signalr实现简单的网页实时聊天。

Socket.IO server端有以下几种不同编程语言的实现:

Socket.IO client端,大多数主流编程语言的也有实现

为什么选socket.io-client-java

本文主要是针对socket.io-client-java的一次实践。

我们团队已经使用Node.js搭建了webserver,并实现了web客户端和webserver的消息互通(即双方都是基于JavaScript的实现)。

但是,有个特殊业务场景,需要在我们后端业务接口中根据业务状态变更向指定的IM会话投递实时消息。

这种需求的实现方案:

  • 方案1,后端业务接口将消息投递到kafka topic,再由webserver消费指定topic,实现消息的实时推送
  • 方案2,后端直接连接webserver,然后投递消息

综合考虑之后,我们选择了方案2。

因此,技术选型上就只有华山一条路——socket.io-client-java

在实现的过程中,也确实是踩了一些坑,所以记录一下,顺便和大家分享一下。

实战案例

现在我们开始socket.io-client-java

之旅吧!

引入socket.io-client-java

Notice: socket.io客户端和服务端的版本要匹配,否则会连不上或者没有反应。

根据socket.io-client-java官方文档给出的版本匹配表格:

Client version Socket.IO server
0.9.x 1.x
1.x 2.x
2.x 3.x / 4.x

因为我们webserver端的socket.io 版本 "socket.io": "^2.4.1"

所以,客户端我只能选择1.x,这里选择1.0.0。

        <dependency>
<groupId>io.socket</groupId>
<artifactId>socket.io-client</artifactId>
<version>1.0.0</version>
</dependency>

maven更新之后,即可使用。


代码实现

package com.zhike.blogmanager.Msg;

import io.socket.client.IO;
import io.socket.client.Socket;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j;
import org.apache.poi.ddf.EscherColorRef;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.stereotype.Component; import java.net.URI;
import java.util.Date; /**
* Created with IntelliJ IDEA.
* User: lenovo
* Date: 2022/6/25
* Time: 21:25
* Description: No Description
*/
@Component
@RequiredArgsConstructor
public class PushMessageManager { private Socket socket; /**
* 消息推送到webserver
* */
public void pushToWebServer() {
//保证只会实例化一次socket
if(socket==null)
{
connentSocket();
System.out.println(socket);
} //构造JSONObject对象
JSONObject data=bulidMsg();
System.out.println("【客户端推送消息】"+data);
//event 要和webserver一致才能接受到消息
socket.emit("2",data); if(!socket.connected())
{
socket.connect();
}
} private void connentSocket(){
try
{
//String url ="http://172.xx.xx.xx:3000";
//String url ="http://172.xx.xx.xx:3001";
String url = "http://172.xx.xx.xx:3002";//web服务器地址以实际为准
IO.Options options = new IO.Options();
options.forceNew = true;
// 失败重连时间间隔
options.reconnectionDelay = 1000;
// 连接超时时间
options.timeout = 5000; socket = IO.socket(URI.create(url), options);
}catch (Exception ex)
{
System.out.println("连接服务器失败,error:"+ex);
}
} /**
* 消息体构造
* 定义须和webserver保持一致,webserver才能解析
* */
private JSONObject bulidMsg()
{
JSONObject data = new JSONObject();
try {
data.put("type", "1");
data.put("from", "[FromUSerId]");
data.put("to", "[ToUserId]");
data.put("msgContent", "Hello World!");
data.put("msgTime", new Date());
} catch (JSONException e) {
throw new AssertionError(e);
}
return data;
}
}

代码中有详细注释,不再赘述。

断线重连的坑

这里还有个巨坑,不知道是否是socket.io-client-java的bug。

如果webserver部署了多个应用并被nginx负载,如下:

server {
listen 3000;
server_name localhost; access_log /data/logs/nginx/webserver/access.log main; location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host; proxy_pass http://webserver-nodes; # enable WebSockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
} upstream webserver-nodes {
# enable sticky session based on IP
# ip_hash; server 172.xx.xx.xx:3001;
server 172.xx.xx.xx:3002;
}

当我设置url="http://172.xx.xx.xx:3000"的时候,就会出现socket会在两台webserver之间disconnect,reconnect的情况。

当时同事反馈,使用JavaScript client连接是正常的。

这个研究了两三天了,尝试了很多方式依然没有解决。

所以,最终我们只能指定连接其中一台webserver。

最后

最后给提了一个issue #715


参考

一个bug肝一周...忍不住提了issue的更多相关文章

  1. 给JDK提的一个bug(关于AbstractQueuedSynchronizer.ConditionObject)

    1. 背景 之前读JUC的AQS源码,读到Condition部分,我当时也写了一篇源码阅读文章--(AbstractQueuedSynchronizer源码解读--续篇之Condition)[http ...

  2. Tomcat一个BUG造成CLOSE_WAIT

    之前应该提过,我们线上架构整体重新架设了,应用层面使用的是Spring Boot,前段日子因为一些第三方的原因,略有些匆忙的提前开始线上的内测了.然后运维发现了个问题,服务器的HTTPS端口有大量的C ...

  3. MySQL关于exists的一个bug

    今天碰到一个很奇怪的问题,关于exists的, 第一个语句如下: SELECT ) FROM APPLY t WHERE EXISTS ( SELECT r.APPLY_ID FROM RECORD ...

  4. 微软BI 之SSIS 系列 - MVP 们也不解的 Scrip Task 脚本任务中的一个 Bug

    开篇介绍 前些天自己在整理 SSIS 2012 资料的时候发现了一个功能设计上的疑似Bug,在 Script Task 中是可以给只读列表中的变量赋值.我记得以前在 2008 的版本中为了弄明白这个配 ...

  5. (四)一个bug的生命周期

    Bug的属性 Bug重现环境 这个应该是我们重现BUG的一个前提,如果没有这个前提,我们可能会无法重现问题,或者根本就无从下手. • 操作系统 这个是一般软件运行的一大前提,基本上所有的软件都依赖于操 ...

  6. 抓到 Netty 一个 Bug,顺带来透彻地聊一下 Netty 是如何高效接收网络连接的

    本系列Netty源码解析文章基于 4.1.56.Final版本 对于一个高性能网络通讯框架来说,最最重要也是最核心的工作就是如何高效的接收客户端连接,这就好比我们开了一个饭店,那么迎接客人就是饭店最重 ...

  7. 由一个bug引发的SQLite缓存一致性探索

    问题 我们在生产环境中使用SQLite时中发现建表报“table xxx already exists”错误,但DB文件中并没有该表.后面才发现这个是SQLite在实现过程中的一个bug,而这个bug ...

  8. Win10系统菜单打不开问题的解决,难道是Win10的一个Bug ?

    Win10左下角菜单打不开,好痛苦,点击右下角的时间也没反应,各种不爽,折磨了我好几天,重装又不忍心,实在费劲,一堆开发环境要安装,上网找了很多方法都不适用.今天偶然解决了,仔细想了下,难道是Win1 ...

  9. 你可能不知道的 NaN 以及 underscore 1.8.3 _.isNaN 的一个 BUG

    这篇文章并不在我的 underscore 源码解读计划中,直到 @pod4g 同学回复了我的 issue(详见 https://github.com/hanzichi/underscore-analy ...

随机推荐

  1. Azure DevOps (十) 通过流水线完成Docker镜像的部署

    上一篇文章中,我们通过azure的流水线完成了镜像推送到镜像仓库中去,本篇文章我们继续开始完成下一步,通过流水线把镜像从仓库拉取到任意一台公网的服务器上去, 完成镜像部署的闭环. 首先我们需要先准备一 ...

  2. gh-ost使用问题记录

    因为 pt-osc 对数据库性能影响较大,且容易造成死锁问题,目前我们在线更改表结构都使用 gh-ost 工具进行修改,这里记录一下使用 gh-ost 过程中的问题,以作记录:首先先复习一下gh-os ...

  3. C#/VB.NET 将RTF转为HTML

    RTF文档即富文本格式(Rich Text Format)的文档.我们在处理文件时,遇到需要对文档格式进行转换时,可以将RTF转为其他格式,如转为DOCX/DOC.PDF或者HTML,以满足程序设计需 ...

  4. Ubuntu 百度飞桨和 CUDA 的安装

    Ubuntu 百度飞桨 和 CUDA 的安装 1.简介 本文主要是 Ubuntu 百度飞桨 和 CUDA 的安装 系统:Ubuntu 20.04 百度飞桨:2.2 为例 2.百度飞桨安装 访问百度飞桨 ...

  5. XCTF练习题---MISC---base÷64

    XCTF练习题---MISC---base÷64 flag:flag{E33B7FD8A3B841CA9699EDDBA24B60AA} 解题步骤: 1.观察题目,下载附件 2.打开附件,观察内容和题 ...

  6. Redis 缓存穿透、缓存击穿、缓存雪崩的解决方案

    一.缓存雪崩 缓存雪崩表示:指缓存同一时间大面积失效或缓存重启又或者第一次启用缓存的情况下,导致请求跳过缓存直接请求数据库,造成数据库短时间内承受大量请求而崩掉. 解决方案: 方案一 缓存数据的过期时 ...

  7. FreeRTOS --(14)队列管理之概述

    转载自 https://blog.csdn.net/zhoutaopower/article/details/107221175 在任何的 OS 中,都需要支持任务与任务,中断与任务之间的数据传输机制 ...

  8. Django学习——路由层之路由匹配、无名分组、有名分组、反向解析

    路由层之路由匹配 """路由你可以看成就是出去ip和port之后的地址""" url()方法 1.第一个参数其实是一个正则表达式 2.一旦第 ...

  9. Vue中mixins、extends、extend和components的作用和区别

    关于mixins:官方文档: https://cn.vuejs.org/v2/guide/mixins.html 一.components Vue.component是用来注册或获取全局组件的方法,其 ...

  10. SpringMVC乱码解决

    解决需要四个步骤:1.jsp页面编码   2.tomcat server.xml编码  3.使用filter对编码进行过滤  4.数据库编码设置 说明:四个地方的编码需要一致:本文使用gbk 1.js ...