WebSocket Mining Pit Kee

Source: Internet
Author: User

Project want to use as a real-time statistics, like 110 police love big screen kind, so used to the websocket, the result stepped on a lot of pits, record again.
Environment: SPRING,SPRINGMVC (4.2.4.RELEASE), TOMCAT7

Problem 1:session object is not the same

HTTP, it's javax.servlet.http.HttpSession.
And WebSocket's time javax.websocket.Session

HTTP session is generally used to save user information, according to the user, the HTTP request when carrying Cookie:jsessionid, to distinguish, to achieve a number of examples. The GetID () of the session of HTTP is Jsessionid, such as BD70D706E4B975EA5CE7418152D3F8DC.

And WebSocket's session has many uses, saves the information, sends the request, may say websocket the front and back end interaction uses the variable and the method, all saves in the WebSocket session.
At the same time, WebSocket's session is based on the front-end to create a connection to multiple cases, that is, the front end of each new websocket open once, create a websocket session. The GetID () of the websocket session is a sequence that increments from 1.

A question about the session synchronization of the HTTP session and WebSocket.
Scenario: The system itself is a standard Web project, but requires the addition of an operational statistics function, real-time monitoring of data changes, then choose more to reflect the real-time websocket, but the original user page and WebSocket page login to do?
Specifically, there are several issues

    1. WebSocket when the connection is established, determine whether the httpsession is logged in, and when not logged in, deny login
    2. HttpSession Disconnect WebSocket when exiting

Current solution:
First, create the corresponding Configurator object and save it temporarily in the object httpsession
"' Javapublic class Websocketsessionconfigurator extends Serverendpointconfig.configurator {
@Override
public void Modifyhandshake (serverendpointconfig config, handshakerequest request, handshakeresponse response) {
When establishing a websocket connection, save the session when the connection is used
HttpSession HttpSession = (HttpSession) request.gethttpsession ();
if (null! = httpSession) {
Config.getuserproperties (). Put (HttpSession.class.getName (), HttpSession);
}
}
}‘‘‘

Then use Configurator in @serverendpoint and save it in OnOpen in the WebSocket session to save HttpSession
' JAVA
@Component
@ServerEndpoint (value = "/xxxx", configurator = websocketsessionconfigurator.class)
public class Xxxxwebsocketcontroller extends Basewebsocketcontroller {

Important ***//WebSocket Session Connection object with class collection (thread safe) private static map<string, session> Wssessionmap = Maps.newconcurrentmap ();//HttpSession corresponds to websocket session with private static map<string, set<string>> Httptowssessionmap = Maps.newconcurrentmap ();//keyprivate final static String Ws_session_ saved in Wssession httpsession KEY = "session";//static variable used to record the current number of online connections private static volatile int onlinecount = 0; @OnOpenpublic void OnOpen (@PathParam ("Para M ") String param, Session wssession, Endpointconfig config) throws IOException {if (!config.getuserproperties (). Contai Nskey (HttpSession.class.getName ())) {//Not logged on Wssession.getasyncremote (). SendText (Toolsutil.strtojson ("Not logged in, please first        Login "," 99 "));  Wssession.close ();    The back-end active disconnection throws an exception, and the front end disconnects return when the front end is judged; }//Httpsessinn save HttpSession HttpSession = (HttpSession) config.getuserproperties (). Get (HttpSession.class.getName (    ));    Wssession.getuserproperties (). Put (Ws_session_key, httpSession); Wssessionmap.put (wssession. GetId (), wssession); The session of the HTTP and the websocket session correspond to if (!httptowssessionmap.containskey (Httpsession.getid ())) {Httptowssessionma    P.put (Httpsession.getid (), Sets.newcopyonwritearrayset ());    } httptowssessionmap.get (Httpsession.getid ()). Add (Wssession.getid ());    Addonlinecount ();    Log information Wssession.getasyncremote (). SendText (Toolsutil.strtojson ("Login Successful", "90")); System.out.println (Messageformat.format ("Wssession id:{0} httpSession id:{1} user logged in WebSocket, current number of connections: {2}", Wssession.getid (), Httpsession.getid (), Onlinecount));}    @OnClosepublic void OnClose (Session wssession, Closereason reason) {if (Wssessionmap.containskey ())) {    User information obtained HttpSession HttpSession = (HttpSession) wssession.getuserproperties (). get (Ws_session_key);    String Wssessionid = Wssession.getid ();    Exit processing Wssessionmap.remove (Wssession.getid ());    Subonlinecount (); if (Httptowssessionmap.containskey (Httpsession.getid ())) {set<string> setsession = HttptoWssessionmap.get (Httpsession.getid ());        Setsession.remove (Wssession.getid ());        if (setsession.size () = = 0) {httptowssessionmap.remove (Httpsession.getid ()); }}//log information System.out.println (Messageformat.format ("Wssession id:{0} httpSession id:{1} user has exited WebSocket, current number of connections: {2} ", Wssessionid, Httpsession.getid (), Onlinecount));} public static void Disconnectbyhttpsession (String httpsessionid) {sendmsgbyhttpsession (Httpsessionid, Toolsutil.strtojson ("User Logout", "99"));}

}
‘‘‘
Finally, when the system logs out and logs out, log off.
"' JAVA
@ResponseBody
@RequestMapping (value= "/exit")
Public String exit (HttpServletRequest req,
HttpServletResponse resp) {
HttpSession session = Req.getsession (false);//Prevent creation of Session
if (session! = NULL) {
Session.removeattribute (Session.getid ());
Disconnecting WebSocket connections
Xxxxwebsocketcontroller.disconnectbyhttpsession (Session.getid ());
}
Return Toolsutil.strtojson ("OK");
}‘‘‘

Issue 2: Failed to inject server in @serverendpoint

In actual use, the discovery @autowired to inject service invalid, reported null pointer exception.
After thinking that this is also normal, Serverendpoint WebSocket object, is actually created when creating a websocket connection, and @autowired is the start of the Web project, the initialization of things. Mining pits, after investigation, found that there are two solutions, according to the spring initialization method, please choose your own:

1, when Contextloaderlistener is used in Web. XML (using Spring's method to initialize the bean), only @serverendpoint Configurator is used for springconfigurator. Or the custom Configurator inherits the Springconfigurator.
"' JAVA
@ServerEndpoint (value = "/xxxxx", configurator = springconfigurator.class)
public class Xxxxxwebsocketcontroller extends Basewebsocketcontroller {
......
}
‘‘‘
Or
"' JAVA
public class Websocketsessionconfigurator extends Springconfigurator {
@Override
public void Modifyhandshake (serverendpointconfig config, handshakerequest request, handshakeresponse response) {
.......
}
}‘‘‘

2, if Dispatcherservlet is used in Web. XML, and the bean is not initialized with Contextloaderlistener (Springmvc way). It is recommended to create a bean by implementing Applicationcontextaware and creating a tool class:

To create a class object
"' JAVA
Import org.springframework.beans.BeansException;
Import Org.springframework.context.ApplicationContext;
Import Org.springframework.context.ApplicationContextAware;
Import org.springframework.stereotype.Component;

public class Springcontexthelper implements Applicationcontextaware {
private static ApplicationContext context = NULL;

@Overridepublic void setApplicationContext(ApplicationContext applicationContext)        throws BeansException {    context = applicationContext;}public static Object getBean(String name){    return context.getBean(name);}

}
‘‘‘
Bean definition:

<!--Spring中bean获取的工具类--><bean id="springContextUtils" class="com.utils.websocket.SpringContextHelper" />

Use:
"' JAVA
Xxxservice = (xxxservice) springcontexthelper.getbean ("Xxxservice");
‘‘‘

Issue 3: An exception occurred calling close () in OnOpen

Scenario: Determine if the user is logged in and deny connection when not logged in.

After the close () of the session in OnOpen is called WebSocket, the connection is broken normally, and OnClose is executed, but the following exception is reported:

"' JAVAjava.lang.IllegalStateException:The WebSocket session had been closed and no method (apart from close ()) could be CA Lled on a closed session
At Org.apache.tomcat.websocket.WsSession.checkState (wssession.java:643)
At Org.apache.tomcat.websocket.WsSession.addMessageHandler (wssession.java:168)
At Org.apache.tomcat.websocket.pojo.PojoEndpointBase.doOnOpen (pojoendpointbase.java:81)
At Org.apache.tomcat.websocket.pojo.PojoEndpointServer.onOpen (pojoendpointserver.java:70)
At Org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.init (wshttpupgradehandler.java:129)
At Org.apache.coyote.abstractprotocol$abstractconnectionhandler.process (abstractprotocol.java:629)
At Org.apache.tomcat.util.net.jioendpoint$socketprocessor.run (jioendpoint.java:310)
At Java.util.concurrent.ThreadPoolExecutor.runWorker (threadpoolexecutor.java:1142)
At Java.util.concurrent.threadpoolexecutor$worker.run (threadpoolexecutor.java:617)
At Java.lang.Thread.run (thread.java:745) "

Online did not find the more appropriate answer, guess is onopen time, Judge is Tomcat in OnOpen time, the processing of close is not enough, but WebSocket itself is initiated by the front-end, so conversion ideas, Instead, the front-end is initiated and the front-end is closed by sending a specific result to the front end to enable the front-end to actively execute the Close method to close the connection.
"' Javasocket = new WebSocket (URL);
Socket.onopen = function (evt) {
if (Evt.data = = "") {
Return "";
}
Convention, 99 for logout of ErrorCode
var data = Json.parse (Evt.data)
if (Data.code = = "99") {
Evt.target.close ();
Alert (Data.code + ":" + data.data);
return;
}
if (data.code! = "00") {
Console.log (Data.code + ":" + data.data);
return;
}

......

};‘‘‘
***

WebSocket Mining Pit Kee

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.