websocket

179 阅读2分钟

什么是webscoket

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

webscoket的优点

  1. 建立在TCP协议之上,服务端的实现比较容易。

  2. 与HTTP有良好的兼容性,默认端口也是80和443端口,并且握手采用的是http协议,不容易屏蔽,能通过各种代理服务器

  3. 数据格式比较轻,性能开销小,通信高效。

  4. 更好的二进制支持。

  5. 没有同源限制,客户端和任意服务端进行通信。

  6. 更好的压缩效果。

websocket 的缺点

  1. 服务器长期维护长连接需要一定的成本
  2. 各个浏览器支持程度不一
  3. websocket 是长连接,受网络限制比较大,需要处理好重连,比如用户进电梯或电信用户打个电话网断了,这时候就需要重连

websocket的使用

1.maven 导入

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

2.创建配置类

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();
	}
}
  1. 服务类
@ServerEndpoint("/websocket/{symbol}")
@Slf4j
@Component
public class WebSocketServer {

	/**
	 * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
	 */
	private static int onlineCount = 0;
	/**
	 * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
	 */
	private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
	/**
	 * 与某个客户端的连接会话,需要通过它来给客户端发送数据
	 */
	private Session session;
	/**
	 * 接收sid
	 */
	private String symbol = "";

	/**
	 * 连接建立成功调用的方法
	 **/
	@OnOpen
	public void onOpen(Session session, @PathParam("symbol") String symbol) {
		log.info("交易对:{}", symbol);
		this.session = session;
		webSocketSet.add(this);
		this.symbol = symbol;
	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		// 从set中删除
		webSocketSet.remove(this);
		// 在线数减1
		subOnlineCount();
		log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
	}

	/**
	 * 收到客户端消息后调用的方法
	 * 
	 * @param message 客户端发送过来的消息
	 **/
	@OnMessage
	public void onMessage(String message, Session session) {
		log.info("收到来自窗口" + symbol + "的信息:" + message);
		// 群发消息
		for (WebSocketServer item : webSocketSet) {
			try {
				item.sendMessage(message);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * @param session
	 * @param error
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		log.error("发生错误");
		error.printStackTrace();
	}

	/**
	 * 实现服务器主动推送
	 */
	public void sendMessage(String message) throws IOException {
		this.session.getBasicRemote().sendText(message);
	}

	/**
	 * 群发自定义消息
	 */
	public static void sendInfo(String message, @PathParam("symbol") String symbol) throws IOException {
		log.info("推送消息到窗口{},推送内容{}", symbol, message);
		for (WebSocketServer item : webSocketSet) {
			try {
				// 这里可以设定只推送给这个sid的,为null则全部推送
				if (symbol == null) {
					item.sendMessage(message);
				} else if (item.symbol.equals(symbol)) {
					item.sendMessage(message);
				}
			} catch (IOException e) {
				continue;
			}
		}
	}

	public static synchronized int getOnlineCount() {
		return onlineCount;
	}

	public static synchronized void addOnlineCount() {
		WebSocketServer.onlineCount++;
	}

	public static synchronized void subOnlineCount() {
		WebSocketServer.onlineCount--;
	}

}

这里有一个问题,就是用tomcat启动时会报错,只需要将

//@Bean
//public ServerEndpointExporter serverEndpointExporter() {
	//	return new ServerEndpointExporter();
	//}
         

注释掉 原因是:

bba3e3677c0041945d5e650cf2f6f78.png