简介
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。其使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
WebSocket事件
- open事件(建立一个websocket连接时触发),事件处理程序即事件回调函数Socket.onopen
- message事件(接收消息时触发),事件处理程序即事件回调函数Socket.onmessage
- error事件(连接发生错误时触发),事件处理程序即事件回调函数Socket.onerror
- close事件(连接关闭时触发),事件处理程序即事件回调函数Socket.onclose
WebSocket方法
- Socket.send(message),使用连接发送数据方法
- Socket.close(),关闭连接方法
数据传输
WebSocket之间的数据传输都是传输字符串,前端建立socket连接,连接到远程websocket服务上,之后每次数据交互都是通过与远程websocket连接交互进而与其他连接到远程webSocket服务的连接进行通信,因此可以自行设置前端与远程webSocket交互的数据格式,例如JSON数据格式,在发送数据时,前端将JSON格式转换成字符串进行发送,前端接受到数据时,接收到的一定是字符串数据,根据开发规约,自行解析数据。
前端实例(H5)
//建立一个websocket连接
let socket=new WebSocket("ws://127.0.0.1:7080/webSocket/"+this.state.userName);
//连接建立回调函数
socket.onopen=function () {
message.info("socket连接已打开");
that.state.userModelShow=false;
that.forceUpdate();
};
//收到消息的处理函数
socket.onmessage=function (msg) {
let data=msg.data;
let arr=data.split("#antsitya#");
let type=arr[0];
let content=arr[1];
let userName="";
let time=new Date();
let onlineCount=that.state.onlineCount;
if(type==="SYS_NOTICE"){
content=arr[1].split("#ONLINECOUNT#")[0];
onlineCount=arr[1].split("#ONLINECOUNT#")[1];
}
if(type==="NEWS_OTHER"){
content=arr[1];
userName=arr[2];
}
let msgNew={
type:type,
userName:userName,
content:content,
time:time,
};
let news=that.state.Msg;
news.push(msgNew);
that.setState({
Msg:news,
onlineCount:onlineCount,
})
};
//连接关闭的回调函数
socket.onclose=function () {
message.info("聊天通道已关闭!")
};
//连接出错的回调函数
socket.onerror=function () {
message.error("socket连接异常")
};
Java实现远程WebSocket服务(Spring Boot)
加入websockt依赖
//pom.xml文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
配置webSocket
//编写WebSocket配置,创建websocket bean实例
//自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
编写接受webSocket处理连接操作类
//消息接收处理 websocket 连接、关闭、发送消息等钩子。
import com.ant.chat_room.Utils.StringUtils;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@Log4j2
@ServerEndpoint("/webSocket/{userId}")
@Component
public class WebSocketServer {
private final String MSG_FIX="#antsitya#";
private static int onlinCount=0;
private static Map<String,WebSocketServer> users= Collections.synchronizedMap(new HashMap<>());
private Session session;
private String userName;
public static synchronized int getOnlinCount(){
return onlinCount;
}
public static synchronized void addOnlineCount(){
WebSocketServer.onlinCount++;
}
public static synchronized void subOnlineCount(){
WebSocketServer.onlinCount--;
}
public static synchronized boolean vaildUserName(String userName){
return users.get(userName)==null;
}
/**
* 客户端建立webSocket连接
* @param session
* @param userName
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userName){
this.session=session;
this.userName=userName;
users.put(userName,this);
addOnlineCount();
log.info(userName+"加入群聊,当前在线人数为"+getOnlinCount());
try{
// this.session.getBasicRemote().sendText("连接成功");
sendToAll("SYS_NOTICE","已加入群聊"+"#ONLINECOUNT#"+getOnlinCount(),userName);
}catch (IOException e){
e.printStackTrace();
log.error("error happen on function onOpen"+e);
}
}
/**
* 客户端管理webSocket连接
*/
@OnClose
public void onClose(){
users.remove(this.userName);
subOnlineCount();
try{
// this.session.getBasicRemote().sendText("连接成功");
sendToAll("SYS_NOTICE","已退出群聊"+"#ONLINECOUNT#"+getOnlinCount(),this.userName);
}catch (IOException e){
e.printStackTrace();
log.error("error happen on function onOpen"+e);
}
log.info(this.userName+"已退出群聊,当前在线人数为:"+getOnlinCount());
}
/**
* 收到客户端出发的消息后出发的方法
*/
@OnMessage
public void onMessage(String message){
log.info("收到客户端发送的消息,内容为:"+message);
try{
//群聊发送消息
if(StringUtils.isNotEmpty(message)){
String[] arrMsg=message.split("@antsitya@");
if(arrMsg.length==3){
sendToAll(arrMsg[0],arrMsg[1],arrMsg[2]);
}else{
log.error("发送信息格式错误");
}
}
}catch (IOException e){
log.error("error happen on function onMessage ",e);
}
}
/**
*
*/
@OnError
public void onError(Session session,Throwable error){
log.error("发生错误session:"+session);
error.printStackTrace();
}
//给特定人员发送消息
public void sendMessageToSomeBody(String userName,String message)throws IOException{
if(users.get(userName)==null) return;
users.get(userName).session.getBasicRemote().sendText(message);
this.session.getBasicRemote().sendText(this.userName+"@"+userName+":"+message);
}
//群发消息
public void sendToAll(String type,String message,String userName) throws IOException{
for(WebSocketServer socketServer:users.values()){
String Msg=type+MSG_FIX;
try{
if(type.equals("SYS_NOTICE")){
Msg=Msg+(socketServer.userName.equals(userName)?"您":userName)+message;
socketServer.session.getBasicRemote().sendText(Msg);
}
if(type.equals("NEWS_OTHER")){
Msg=Msg+message+MSG_FIX+userName;
if(!socketServer.userName.equals(userName)){
socketServer.session.getBasicRemote().sendText(Msg);
}
}
}catch (IOException e){
continue;
}
}
}
}
评论区