The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method 已解决

There is a problem that webSocket automatically disconnects, which has been resolved, please see the blog:

webSocket java.io.EOFException: null Added heartbeat mechanism to solve

Then another error was reported:

java.lang.IllegalStateException: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
	at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.checkState(WsRemoteEndpointImplBase.java:1224) ~[tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.textStart(WsRemoteEndpointImplBase.java:1187) ~[tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendString(WsRemoteEndpointImplBase.java:190) ~[tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendText(WsRemoteEndpointBasic.java:37) ~[tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at com.everestfortune.cf.config.webSocket.WebSocketServer.sendMessage(WebSocketServer.java:202) ~[classes!/:0.0.1-SNAPSHOT]
	at com.everestfortune.cf.config.webSocket.WebSocketServer.onMessage(WebSocketServer.java:155) ~[classes!/:0.0.1-SNAPSHOT]
	at sun.reflect.GeneratedMethodAccessor176.invoke(Unknown Source) ~[na:na]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_265]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_265]
	at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBase.onMessage(PojoMessageHandlerWholeBase.java:80) [tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:394) [tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageText(WsFrameServer.java:119) [tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:495) [tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:294) [tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:133) [tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:82) [tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:171) [tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:151) [tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148) [tomcat-embed-websocket-8.5.29.jar!/:8.5.29]
	at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54) [tomcat-embed-core-8.5.29.jar!/:8.5.29]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) [tomcat-embed-core-8.5.29.jar!/:8.5.29]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.29.jar!/:8.5.29]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.29.jar!/:8.5.29]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_265]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_265]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.29.jar!/:8.5.29]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_265]

 

 The methods for websocket to push data are:

  1. session.getBasicRemote().sendText(message); //同步发送

  2. session.getAsyncRemote().sendText(message); //异步发送

After testing, in the case of high concurrency, both sending methods will throw the above exception. The reason is that multiple threads use the same session to send at the same time .

After making the following changes:

synchronized(session){
    session.getAsyncRemote().sendText(message);
}

After testing, asynchronous sending will still throw the above exception, and synchronization will not occur. Guess: Asynchronous should be sent by a new thread. Even if synchronized is used, there will be opportunities for two sessions to be operated by different threads at the same time.

Decided to use:

synchronized(session){

    session.getBasicRemote().sendText(message);

}

//When the network is very good. Multiple threads send data in the same session

At this point, if you are using a single session, the problem should be solved.

 

The definition of webSocket Session is as follows:

/**
 * 与某个客户端的连接会话,需要通过它来给客户端发送数据
 */
private Session session;

If there are multiple clients, or the same user, or open multiple browsers, open multiple pages

Session is different at this time.

Locking one of the Sessions at this time cannot solve this problem.

 

I used to lock a global static object to solve the problem of simultaneous access by multiple threads:

	/**
	 * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
	 */
	private static final ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();


	/**
	 * 实现服务器主动推送
	 */
	private void sendMessage(String message) throws IOException {
		// 尝试过锁住方法,还是不行,这里锁住webSocketMap,让多线程,访问不同对象,也能同步
		synchronized(webSocketMap){
			JSONObject jsonObject = JSON.parseObject(message);
			String toUserId = jsonObject.getString("user");
			if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
				webSocketMap.get(toUserId).getSession().getBasicRemote().sendText(message);
			}
		}
		//this.session.getBasicRemote().sendText(message);
	}

 

Since then, this issue has never been reported again

 

supplement:

At the beginning of adding synchronized to the method, because this method is not static, it can only lock the current object, not the class.

If synchronized is added to a non-static method, it means synchronized (the object of the calling method) {}, if it is added to a static method, it means synchronized (class.class) {}

 

 

 

Guess you like

Origin blog.csdn.net/u013282737/article/details/109217177