1.问题原因
相信大家在进行SpringBoot的WS编程过程中或多或少都可能遇到过此问题。
这个问题的原因是:WebSocket的客户端对应的服务器端的EndPoint本来就在给客户端发送数据,现在又人它发送数据,造成了写的冲突。
2.解决方案
2.1. 判断当前EndPoint处在准备好的状态
发送给客户端之前,都需要检查当前的EndPoint是否处于一个准备好的状态。故我们可以在发送之前做如下判断:
Session session = endpoint.session;
if (session.isOpen()) {
// 发送数据到ws客户端
endpoint.sendMessage(message);
}
但是光有这一步是不够的,因为同时两个线程进来,都判断了session为打开状态,一个还没发送完,另一个线程又要发送数据。必然造成冲突。
2.2. session同步
这样我们必须让同一个session,只能有一个线程进行写操作。我们可以这样写:
Session session = endpoint.session;
synchronized (session) {
if (session.isOpen()) {
endpoint.sendMessage(message);
}
}
这样操作完之后,我们对应同一个session,就只有一个线程在写了。当然你也可以使用更加复杂的锁,其机理是一致的。
3.思考
本问题的来源就是资源的争抢,其实此类问题在多处都能找到类似的影子。就比如sqlite数据库在写操作的时候直接锁库等等。我们在进行编程的过程中,一定要注意对于从操作系统申请到的资源的管理,一个是防止过度争抢,一个是避免出现资源浪费(比如内存泄漏)。