What is websocket
Websocket is a protocol for full duplex communication over a single TCP connection. After the websocket connection is successful, the server and the client can communicate in two directions. In the scenario of message push, websocket can save server resources and bandwidth better than polling, and can communicate in real time.
- It has good compatibility with HTTP protocol. The default port is also 80 and 443, and the handshake phase uses HTTP protocol, so it is not easy to shield the handshake, and it can pass through various HTTP proxy servers.
- TCP dependent
- The data format is light, the performance overhead is small, and the communication is efficient.
- You can send text or binary data.
- There is no source restriction, the client can communicate with any server.
- The protocol identifier is WS (or WSS if encrypted), and the server address is the URL.
Using websocket in springboot
After a brief understanding of websocket, let’s put it into practice. There are many ways to implement websocket server in springboot. Here I choose Tomcatjavax.websocket.server
The API of,The demo address will be given at the end
- Introducing Maven dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- Create a bean to process the websocket request, and declare the websocket URL accepted by the current bean through the serverendpoint
Why @ controller is declared here will be explained later
import org.springframework.stereotype.Controller;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint(value = "/message_websocket")
@Controller
public class MsgWebsocketController {
@OnOpen
public void onOpen(Session session) {
//Authentication first. If authentication passes, websocketsession will be stored. Otherwise, the connection will be closed. The authentication code is omitted here
WebSocketSupport.storageSession(session);
System.out.println("session open. ID:" + session.getId());
}
/**
*Method called by connection close
*/
@OnClose
public void onClose(Session session) {
System.out.println("session close. ID:" + session.getId());
}
/**
* call method after receiving client message
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("get client msg. ID:" + session.getId() + ". msg:" + message);
}
/**
*Called when an error occurs
*/
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
}
- Declare serverendpoint exporter
@Configuration
public class WebsocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
So far, the websocket server has been built, and the client can communicate with the server
The server pushes messages to the client throughsession.getBasicRemote().sendText(message);
that will do
Analysis of source code
Let’s take a look at how these short lines of code build websocket server for us
ServerEndpointExporter
Focus on the content in the red box below
- ServerEndpointExporter implements SmartInitializingSingleton, which will be called after the bean instantiation is finished.
afterSingletonsInstantiated
- Get all tags from the spring context
@ServerEndpoint
The name of the bean
In fact, the msgwebsocketcontroller we declare is not only marked with @ controller, but just to register it in the spring container to facilitate the registration of serverendpoint. The mark @ controller is more in line with the spring development specification
3 ~ 4. Mark all tags through servercontainer@ServerEndpoint
Bean registration for
The default implementation class of servercontainer is wsservercontainer. It will map our serverendpoint, url = > the corresponding class, and then call the specified method for different events (for example, call the tag when establishing a connection)@Onopen
This is a little spring dispatcher servlet flavor, interested students can take a look at it
After learning what spring has done for us, let’s refine our demo
Set up a session manager
When we want to push messages to the client, first we need to find the connection between the client and the server, that is, websocketsession
Although websocketsession has been stored in wsservercontainer, there is no way to locate the specified session directly through the sessionid or our business ID, so we need to implement our own session manager
final ConcurrentHashMap<Object, Session> sessionPool = new ConcurrentHashMap<>();
Use concurrent HashMap to manage
Distributed push solution
As shown in the figure, user 1 establishes websocket with server a, and user 2 establishes websocket with server B. how can user 1 push a message to user 2?
Websocketsession is actually a network connection. Unlike our traditional session, which can be serialized to redis, only each server can manage its own websocketsession. Therefore, server a notifies server B that you want to push a message to user 2.
A relatively simple and effective implementation method, using message queue, as shown in the following figure
The advantage of this scheme is that it is easy to implement, but the disadvantage is that each server needs to judge whether there is a specified websocket session. If the scheme is detailed, it needs to maintain the relationship between the user session and each server, so that the message can be directly pushed to the specified server
Other issues
During the test, it is found that when the client is disconnected, the server can still call the session push method, and the server will always hold the invalid session
At present, the solution is to set the maximum idle time of websocketsession(session.setMaxIdleTimeout(milliseconds);
)After this time, the server will close the session. The front end sends a heartbeat packet regularly to maintain the session. When the above situation occurs, the server will not hold the session all the time
Full demo address
For details of demo, please refer to readme in the project address
Github 👉 https://github.com/TavenYin/taven-springboot-learning/tree/master/sp-websocket
Gitee 👉 https://gitee.com/yintianwen7/taven-springboot-learning/tree/master/sp-websocket
reference resources
http://www.ruanyifeng.com/blog/2017/05/websocket.html
Part of the code reference a brother’s blog, but due to a little long time, can’t find, here to say sorry
If you feel that you have gained something, you can pay attention to my official account.