java.lang.IllegalStateException
。调用onClose
方法我得到了套接字已经关闭的异常。因此,我不能清理在Web套接字会话关闭时停止的不同Thread中的一些东西。如果用户在没有重新加载页面的情况下关闭会话(它基本上是websocket上的服务器端终端),一切都很好。我在tomcat8上。
问题。
以下是为websocket连接提供服务的代码。
@ServerEndpoint(value = "/ws/{clientId}", configurator = HttpSessionConfigurator.class)
public class WSSession {
public static final long DEFAULT_TIMEOUT = 3600000;
public static final int DEFAULT_TIMEOUT_IN_SECONDS = 3600;
private Session wsSession;
private HttpSession httpSession;
private static final ConfigService configService;
static {
configService = ConfigServiceFactory.getConfigService(System
.getenv("ENVRIRONMENT"));
}
@OnOpen
public void onOpen(@PathParam("clientId") String clientId, Session session,
EndpointConfig config) throws IOException {
Logger logger = Logger.getLogger(clientId);
try {
FileHandler fh = new FileHandler(configService.logDirectory()
.toString() + "/" + clientId);
SimpleFormatter formatter = new SimpleFormatter();
fh.setFormatter(formatter);
logger.addHandler(fh);
logger.setLevel(Level.INFO);
} catch (SecurityException | IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("Got ID: " + clientId);
// TODO: Get the max timeout from configuration
session.setMaxIdleTimeout(DEFAULT_TIMEOUT);
ConnectionDetails cd = configService.getConnectionDetails(clientId);
this.wsSession = session;
this.httpSession = (HttpSession) config.getUserProperties().get(
HttpSession.class.getName());
if (this.httpSession.getAttribute(SessionProperties.WS_SESSION.value()) != null
&& this.httpSession.getAttribute(SessionProperties.WS_SESSION
.value()) != session) {
Session wSession = (Session) this.httpSession
.getAttribute(SessionProperties.WS_SESSION.value());
if (wSession.isOpen()) {
wSession.close();
}
}
// TODO: Code changes for password based login
// For now there is no password login.
// TODO: For now the passphrase is NULL and strict checking is disabled
this.wsSession = session;
try {
Connection connection = new Connection(cd.getHost(), cd.getPort());
connection.connect();
boolean authenticated = connection.authenticateWithPublicKey(
cd.getUserName(), cd.getPrivateKey().toCharArray(), null);
if (authenticated) {
ch.ethz.ssh2.Session sshSession = connection.openSession();
sshSession.requestPTY("xterm", 120, 40, 14, 14, null);
OutputStream out = sshSession.getStdin();
InputStream in = new StreamGobbler(sshSession.getStdout());
sshSession.startShell();
Basic basicRemote = session.getBasicRemote();
Async asyncRemote = session.getAsyncRemote();
httpSession.setAttribute(SessionProperties.CLIENT_ID.value(),
clientId);
httpSession.setAttribute(SessionProperties.SSH_SESSION.value(),
sshSession);
httpSession.setAttribute(SessionProperties.IN_SSH.value(), out);
httpSession.setAttribute(SessionProperties.OUT_SSH.value(), in);
httpSession.setAttribute(
SessionProperties.BASIC_REMOTE.value(), basicRemote);
httpSession.setAttribute(SessionProperties.WS_SESSION.value(),
wsSession);
httpSession.setAttribute(
SessionProperties.ASYNC_REMOTE.value(), asyncRemote);
Thread worker = new Thread(new OutputTask(httpSession,
wsSession));
worker.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
// IN_SSH is connection from this machine to remote machine.
// OUT_SSH is connection from this remote machine to this machine.
byte[] bytes = message.getBytes();
OutputStream out = (OutputStream) httpSession
.getAttribute(SessionProperties.IN_SSH.value());
out.write(bytes);
}
@OnClose
public void onClose(Session session) throws IOException {
if (session.isOpen()) {
try {
session.close();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
我有一个在socket打开的情况下运行的线程,但是当用户重新加载时,我不会在输出中看到Exiting OutputTask
- 它会在正常的套接字关闭时打印出来。该线程的代码。
@Override
public void run() {
InputStream stream = (StreamGobbler) session
.getAttribute(SessionProperties.OUT_SSH.value());
Basic basicRemote = (Basic) session
.getAttribute(SessionProperties.BASIC_REMOTE.value());
int read = 0;
byte[] bt = new byte[1024];
try {
while (wsSession.isOpen() && (read = stream.read(bt)) != -1) {
logger.info(new String(bt));
basicRemote.sendText(new String(Arrays.copyOf(bt, read)));
// TODO: Add logging and finalize code
}
} catch (SecurityException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
Handler[] handlers = logger.getHandlers();
for (Handler h : handlers) {
h.close();
}
logger = null;
if (wsSession.isOpen()) {
wsSession.close();
}
if (stream != null) {
stream.close();
}
System.out.println("Exiting OutputTask");
session.invalidate();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
用户重新加载页面时出错。
java.lang.IllegalStateException: Message will not be sent because the WebSocket session has been closed
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.writeMessagePart(WsRemoteEndpointImplBase.java:378)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessage(WsRemoteEndpointImplBase.java:335)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessageBlock(WsRemoteEndpointImplBase.java:264)
at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:536)
at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:464)
at org.apache.tomcat.websocket.WsSession.close(WsSession.java:441)
at org.apache.tomcat.websocket.WsSession.close(WsSession.java:435)
at com.example.websocket.wss.onClose(WSSession.java:130)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.tomcat.websocket.pojo.PojoEndpointBase.onClose(PojoEndpointBase.java:107)
at org.apache.tomcat.websocket.WsSession.fireEndpointOnClose(WsSession.java:508)
at org.apache.tomcat.websocket.WsSession.onClose(WsSession.java:491)
at org.apache.tomcat.websocket.WsFrameBase.processDataControl(WsFrameBase.java:342)
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:284)
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130)
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60)
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203)
at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:194)
at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:95)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:653)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)