Java使用WebSocket

0

之前有一篇WebSocket的视频通话教程,那个主要不是讲怎么使用WebSocket,这篇文章主要就说一下WebSocket的使用。

首先要用到的是最新的Tomcat8,因为要支持JavaEE7JavaEE7WebSocket纳入规范的。

下面是代码:

@ServerEndpoint("/face/accept/{rid}")
public class FaceSocket {

	@OnOpen
	public void onOpen(Session session, @PathParam("rid") String rid) {
		// 打开一个websocket时调用方法,上面的注解有点类似springMVC
		session.getAsyncRemote().sendText("逗比你好!");
	}

	@OnClose
	public void onClose(Session session, @PathParam("rid") String rid) {
		// 关闭时调用方法,这个方法好像存在问题,而且不要手动关闭session
	}

	@OnMessage
	public void onMessage(String message, Session session, @PathParam ("rid")String rid) {
		// 接受到消息时调用方法,session就是用户的session,message就是接受到的用户的信息
		session.getAsyncRemote().sendText(message);
	}

}

这里要说一下上面的onClose方法,这个方法里面:

  1. 不要使用session发送消息给用户
  2. 不要手动调用close方法
  3. 不能有任何异常抛出

以上三种情况都会引起Message will not be sent because the WebSocket session has been closed,后来发现升级到Tomcat9后就没有上面的错误了,估计应该是Tomcat8的BUG。

下面是JS部分(使用sendersend方法就可以发送消息了):

var sender;
function initWebSocket(url) {
	if(!WebSocket) {
		alert("你的浏览器不支持WebSocket!");
		return null;
	}
	var webSocket = new WebSocket(url);
	webSocket.onerror = function(event) {
		console.log("websocket发送错误:" + event.data);
	}
	webSocket.onopen = function(event) {
		console.log("websocket打开");
	}
	webSocket.onclose = function(event) {
		console.log("websocket关闭");
	}
	webSocket.onmessage = function(event) {
		// websocket收到消息
		var message = JSON.parse(event.data);
		logMessage(message.content, true);
	}
	sender = {
		send : function(message) {
			// 调用websocket的发送
			webSocket.send(message);
		}
	}
}

URL的格式:ws://域名/face/accept/rid

17-Apr-2018 11:59:37.595 严重 [http-nio-8080-exec-5] org.apache.tomcat.websocket.pojo.PojoEndpointBase.onError No error handling configured for [com.acgist.web.websocket.AcgistVideo] and the following error occurred
 java.io.EOFException
	at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1167)
	at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1107)

这个错误时没有添加@OnError这个处理方法导致的。

如果经常出现EOFException,可以检查Nginx配置:

proxy_read_timeout      1200s;
keepalive_timeout       1200s;

参考:https://www.codeleading.com/article/12972598394/

事实证明依然存在问题。

如果提示:

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

这个问题之前使用异步发送,改为同步发送暂时就没有发现问题了:

synchronized (session) {
	try {
		session.getBasicRemote().sendText(message);
//		session.getAsyncRemote().sendText(message);			
	} catch (IOException e) {
		LOGGER.error("WebSocket发送异常:{}", message, e);
	}
}