如何用apache建设网站,郴州网站建设设计,专业建站公司主要做什么,8小8x人2022成免费入口socketio 安装配置
Socket.IO是一个完全由JavaScript实现、基于Node.js、支持WebSocket的协议用于实时通信、跨平台的开源框架#xff0c;它包括了客户端的JavaScript和服务器端的Node.js。
Socket.IO除了支持WebSocket通讯协议外#xff0c;还支持许多种轮询#xff08;P…socketio 安装配置
Socket.IO是一个完全由JavaScript实现、基于Node.js、支持WebSocket的协议用于实时通信、跨平台的开源框架它包括了客户端的JavaScript和服务器端的Node.js。
Socket.IO除了支持WebSocket通讯协议外还支持许多种轮询Polling机制以及其它实时通信方式并封装成了通用的接口并且在服务端实现了这些实时机制的相应代码。Socket.IO实现的Polling通信机制包括Adobe Flash Socket、AJAX长轮询、AJAX multipart streaming、持久Iframe、JSONP轮询等。Socket.IO能够根据浏览器对通讯机制的支持情况自动地选择最佳的方式来实现网络实时应用。
GitHubhttps://github.com/mrniko/netty-socketio
安装 netty-socketio 依赖
dependencygroupIdcom.corundumstudio.socketio/groupIdartifactIdnetty-socketio/artifactIdversion1.7.23/version
/dependency这个配置写在服务端客户端不用写主要是一些 socket.io 的配置信息。
#socket.io 配置
socketio.host127.0.0.1(别写 localhost写服务器的 ip)
socketio.port9999
# 设置最大每帧处理数据的长度防止他人利用大数据来攻击服务器
socketio.maxFramePayloadLength1048576
# 设置 http 交互最大内容长度
socketio.maxHttpContentLength1048576
# socket连接数大小如只监听一个端口 boss 线程组为 1 即可
socketio.bossCount1
socketio.workCount100
socketio.allowCustomRequeststrue
# 协议升级超时时间毫秒默认 10 秒。HTTP握手升级为 ws 协议超时时间
socketio.upgradeTimeout1000000
# Ping 消息超时时间毫秒默认 60 秒这个时间间隔内没有接收到心跳消息就会发送超时事件
socketio.pingTimeout6000000
# Ping 消息间隔毫秒默认 25 秒。客户端向服务器发送一条心跳消息间隔
socketio.pingInterval25000创建 Socketio 配置类
package com.mslmsxp.mathscat.config;import com.corundumstudio.socketio.SocketConfig;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;Configuration
public class SocketioConfig {Value(${socketio.host})private String host;Value(${socketio.port})private Integer port;Value(${socketio.bossCount})private int bossCount;Value(${socketio.workCount})private int workCount;Value(${socketio.allowCustomRequests})private boolean allowCustomRequests;Value(${socketio.upgradeTimeout})private int upgradeTimeout;Value(${socketio.pingTimeout})private int pingTimeout;Value(${socketio.pingInterval})private int pingInterval;Beanpublic SocketIOServer socketIOServer() {SocketConfig socketConfig new SocketConfig();socketConfig.setTcpNoDelay(true);socketConfig.setSoLinger(0);com.corundumstudio.socketio.Configuration config new com.corundumstudio.socketio.Configuration();config.setSocketConfig(socketConfig);config.setHostname(host);config.setPort(port);config.setBossThreads(bossCount);config.setWorkerThreads(workCount);config.setAllowCustomRequests(allowCustomRequests);config.setUpgradeTimeout(upgradeTimeout);config.setPingTimeout(pingTimeout);config.setPingInterval(pingInterval);return new SocketIOServer(config);}Beanpublic SpringAnnotationScanner springAnnotationScanner() {return new SpringAnnotationScanner(socketIOServer());}
}public SpringAnnotationScanner springAnnotationScanner()
用于扫描netty-socketio的注解比如 OnConnect、OnEvent 注意如果想要SocketIO 的注解生效必须注入SpringAnnotationScanner 这个类。 说明OnDisconnectOnConnectOnEvent都属于SocketIO的注解想要注解生效则必须在配置配配置SpringAnnotationScanner; OnConnect: 监听客户端连接 OnDisconnect 监听客户端断开连接 OnEvent (value“text”) 用于监听客户端发送的消息,value的值就是客户端请求的唯一标识如socket.emit(‘text’,‘要发送的消息’);
注意SocketIOMessageEventHandler 继承了ObservableObservable是JDK自带的观察者模式中的类继承这个类的类说明是被观察者。
ConcurrentHashMap
ConcurrentHashMap 和 HashMap 一样是一个存放键值对的容器。使用 hash 算法 来获取值的地址因此时间复杂度是 O(1)。查询非常快。 同时ConcurrentHashMap 是线程安全的 HashMap。专门用于多线程环境。
HashMap
HashMap 是线程不安全的因为 HashMap 中操作都没有加锁因此在多线程环境下会导致数据覆盖之类的问题所以在多线程中使用 HashMap 是会抛出异常的。
HashTable
HashTable 是线程安全的但是 HashTable 只是单纯的在 put() 方法上加上 synchronized。保证插入时阻塞其他线程的插入操作。虽然安全但因为设计简单所以性能低下。
ConcurrentHashMap
ConcurrentHashMap是线程安全的ConcurrentHashMap 并非锁住整个方法而是通过原子操作和局部加锁的方法保证了多线程的线程安全且尽可能减少了性能损耗。
java.lang.IllegalStateException: Failed to execute CommandLineRunner
······
Caused by: java.nio.channels.UnresolvedAddressException: nullsocketio 业务层
package com.mslmsxp.mathscat.socketio;import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;Slf4j
Component
public class SocketService{Autowiredprivate SocketIOServer socketIoServer;OnConnectpublic void onConnect(SocketIOClient client) {String username client.getHandshakeData().getSingleUrlParam(username);log.info(客户端: client.getRemoteAddress() sessionId: client.getSessionId() username: username 已连接);}OnDisconnectpublic void onDisconnect(SocketIOClient client) {log.info(客户端: client.getSessionId() 断开连接);MapString, Object paramMap new HashMap();paramMap.put(type, disconnect);paramMap.put(sessionId, client.getSessionId().toString());log.error(paramMap.toString());}
}socket 会话本地存储
package com.mslmsxp.mathscat.socketio;import com.corundumstudio.socketio.SocketIOClient;
import io.micrometer.common.util.StringUtils;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;Component
public class ClientCache {private static MapString, HashMapUUID, SocketIOClient concurrentHashMap new ConcurrentHashMap();public void saveClient(String userId, UUID sessionId, SocketIOClient socketIOClient) {if (StringUtils.isNotBlank(userId)) {HashMapUUID, SocketIOClient sessionIdClientCache concurrentHashMap.get(userId);if (sessionIdClientCache null) {sessionIdClientCache new HashMap();}sessionIdClientCache.put(sessionId, socketIOClient);concurrentHashMap.put(userId, sessionIdClientCache);}}public HashMapUUID, SocketIOClient getUserClient(String userId) {return concurrentHashMap.get(userId);}public void deleteSessionClient(String userId, UUID sessionId) {concurrentHashMap.get(userId).remove(sessionId);}
}启动 socketio server
方法一PostConstruct 注解 注入完成 启动
package com.mslmsxp.mathscat.socketio;import com.corundumstudio.socketio.SocketIOServer;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;Component
public class SocketioServer {Autowiredprivate SocketIOServer server;PostConstructvoid init() {server.start();System.out.println(socketio launch);}}该注解是 Java jdk 提供的注解而不是 Spring 框架提供的 JavaEE5 引入了 PostConstruct 和 PreDestroy 两个作用于 Servlet 生命周期的注解实现 Bean 初始化之前和销毁之前的自定义操作。
该注解的方法在整个 Bean 初始化中的执行顺序
Constructor(构造方法) Autowired(依赖注入) PostConstruct(注释的初始化方法) 官方文档https://docs.oracle.com/javase/8/docs/api/javax/annotation/PostConstruct.html PostConstruct 注解的功能当依赖注入完成后用于执行初始化的方法并且只会被执行一次。
2023-02-20T18:33:27.12008:00 INFO 16508 --- [ restartedMain] c.c.socketio.SocketIOServer : Session store / pubsub factory used: MemoryStoreFactory (local session store only)
2023-02-20T18:33:27.30008:00 INFO 16508 --- [ntLoopGroup-2-1] c.c.socketio.SocketIOServer : SocketIO server started at port: 9999
socketio launch
2023-02-20T18:33:27.49008:00 INFO 16508 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2023-02-20T18:33:27.50908:00 INFO 16508 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 5000 (http) with context path
2023-02-20T18:33:27.51508:00 INFO 16508 --- [ restartedMain] c.mslmsxp.mathscat.MathscatApplication : Started MathscatApplication in 1.594 seconds (process running for 2.074)方法二使用 CommandLineRunner 启动
package com.mslmsxp.mathscat.socketio;import com.corundumstudio.socketio.SocketIOServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;Component
public class SocketioServer implements CommandLineRunner {Autowiredprivate SocketIOServer server;Overridepublic void run(String... args) throws Exception {this.server.start();System.out.println(Command Line Start Socketio Server);}
}最后等 http Tomcat 启动完成之后 进行启动。
2023-02-20T18:36:58.70308:00 INFO 31684 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2023-02-20T18:36:58.72508:00 INFO 31684 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 5000 (http) with context path
2023-02-20T18:36:58.73408:00 INFO 31684 --- [ restartedMain] c.mslmsxp.mathscat.MathscatApplication : Started MathscatApplication in 1.907 seconds (process running for 2.505)
2023-02-20T18:36:58.73608:00 INFO 31684 --- [ restartedMain] c.c.socketio.SocketIOServer : Session store / pubsub factory used: MemoryStoreFactory (local session store only)
Command Line Start Socketio Server
2023-02-20T18:36:58.94708:00 INFO 31684 --- [ntLoopGroup-2-1] c.c.socketio.SocketIOServer : SocketIO server started at port: 9999客户端运行测试
SocketIO 官方网站https://socket.io/zh-CN/
使用 script 引入
script src/socket.io/socket.io.js/script使用 ESM 引入
script typemoduleimport { io } from https://cdn.socket.io/4.3.2/socket.io.esm.min.js;
/script前端代码案例
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleSocket Client First/title
/headbodydivSocket Client/divscript typemoduleimport { io } from https://cdn.socket.io/4.3.2/socket.io.esm.min.js;const socket io.connect(ws://localhost:3000?usernamehelloworld)socket.on(connection, (socket) {console.log(socket.id); // x8WIv7-mJelg7on_ALbx});socket.on(connect, () {console.log(socket.id); // x8WIv7-mJelg7on_ALbx});socket.on(disconnect, () {console.log(socket.id); // undefined});/script
/body/html服务器端运行结果
2023-02-20T19:53:59.65108:00 INFO 14856 --- [tLoopGroup-3-40] c.m.mathscat.socketio.SocketService : 客户端:/127.0.0.1:63182 sessionId:64971bce-996e-4d2f-a235-800d3ac1d4a6 username: helloworld已连接