Java WebSocket客户端突然关闭连接
我正在尝试使用WebSocket通过服务器模拟客户端到客户端的通信 这个想法是: 客户端A要向客户端B发送消息A向服务器发送消息,服务器通过查找会话映射来确定B是否有活动会话。然后服务器通过B的会话将消息转发到B A和B都能够连接到服务器,并能够将消息发送到服务器。但是服务器没有发回任何东西(没有触发Java WebSocket客户端突然关闭连接,java,websocket,wildfly,java-websocket,jsr356,Java,Websocket,Wildfly,Java Websocket,Jsr356,我正在尝试使用WebSocket通过服务器模拟客户端到客户端的通信 这个想法是: 客户端A要向客户端B发送消息A向服务器发送消息,服务器通过查找会话映射来确定B是否有活动会话。然后服务器通过B的会话将消息转发到B A和B都能够连接到服务器,并能够将消息发送到服务器。但是服务器没有发回任何东西(没有触发@OnMessage)。在服务器端,我得到了以下信息:java.io.IOException:一个现有连接被远程主机强制关闭 在客户端,我在OnError()方法中抛出了这个: java.lang.
@OnMessage
)。在服务器端,我得到了以下信息:java.io.IOException:一个现有连接被远程主机强制关闭
在客户端,我在
OnError()方法中抛出了这个:
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.String
at org.glassfish.tyrus.core.TyrusSession.notifyMessageHandlers(TyrusSession.java:576)
at org.glassfish.tyrus.core.TyrusEndpointWrapper.onMessage(TyrusEndpointWrapper.java:871)
at org.glassfish.tyrus.core.TyrusWebSocket.onMessage(TyrusWebSocket.java:212)
at org.glassfish.tyrus.core.frame.TextFrame.respond(TextFrame.java:139)
at org.glassfish.tyrus.core.ProtocolHandler.process(ProtocolHandler.java:807)
at org.glassfish.tyrus.client.TyrusClientEngine$TyrusReadHandler.handle(TyrusClientEngine.java:747)
at org.glassfish.tyrus.container.jdk.client.ClientFilter.processRead(ClientFilter.java:226)
at org.glassfish.tyrus.container.jdk.client.Filter.onRead(Filter.java:134)
at org.glassfish.tyrus.container.jdk.client.Filter.onRead(Filter.java:136)
at org.glassfish.tyrus.container.jdk.client.Filter.onRead(Filter.java:136)
at org.glassfish.tyrus.container.jdk.client.TransportFilter$4.completed(TransportFilter.java:299)
at org.glassfish.tyrus.container.jdk.client.TransportFilter$4.completed(TransportFilter.java:283)
at sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:126)
at sun.nio.ch.Invoker$2.run(Invoker.java:218)
at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
这是我从Wireshark得到的:
No. Time Source Destination Protocol Length Info
5065 23.807645 127.0.0.1 127.0.0.1 TCP 108 50765 → 8080 [SYN] Seq=0 Win=64240 Len=0 MSS=65495 WS=256 SACK_PERM=1
Frame 5065: 108 bytes on wire (864 bits), 56 bytes captured (448 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50765, Dst Port: 8080, Seq: 0, Len: 0
No. Time Source Destination Protocol Length Info
5066 23.807689 127.0.0.1 127.0.0.1 TCP 108 8080 → 50765 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1
Frame 5066: 108 bytes on wire (864 bits), 56 bytes captured (448 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 8080, Dst Port: 50765, Seq: 0, Ack: 1, Len: 0
No. Time Source Destination Protocol Length Info
5067 23.807727 127.0.0.1 127.0.0.1 TCP 84 50765 → 8080 [ACK] Seq=1 Ack=1 Win=525568 Len=0
Frame 5067: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50765, Dst Port: 8080, Seq: 1, Ack: 1, Len: 0
No. Time Source Destination Protocol Length Info
5070 23.814122 127.0.0.1 127.0.0.1 HTTP 454 GET /ChatApp/chat/D HTTP/1.1
Frame 5070: 454 bytes on wire (3632 bits), 229 bytes captured (1832 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50765, Dst Port: 8080, Seq: 1, Ack: 1, Len: 185
Hypertext Transfer Protocol
No. Time Source Destination Protocol Length Info
5071 23.814169 127.0.0.1 127.0.0.1 TCP 84 8080 → 50765 [ACK] Seq=1 Ack=186 Win=525568 Len=0
Frame 5071: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 8080, Dst Port: 50765, Seq: 1, Ack: 186, Len: 0
No. Time Source Destination Protocol Length Info
5074 23.815741 127.0.0.1 127.0.0.1 HTTP 584 HTTP/1.1 101 Switching Protocols
Frame 5074: 584 bytes on wire (4672 bits), 294 bytes captured (2352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 8080, Dst Port: 50765, Seq: 1, Ack: 186, Len: 250
Hypertext Transfer Protocol
No. Time Source Destination Protocol Length Info
5075 23.815771 127.0.0.1 127.0.0.1 TCP 84 50765 → 8080 [ACK] Seq=186 Ack=251 Win=525312 Len=0
Frame 5075: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50765, Dst Port: 8080, Seq: 186, Ack: 251, Len: 0
No. Time Source Destination Protocol Length Info
5078 23.843679 127.0.0.1 127.0.0.1 TCP 108 50766 → 8080 [SYN] Seq=0 Win=64240 Len=0 MSS=65495 WS=256 SACK_PERM=1
Frame 5078: 108 bytes on wire (864 bits), 56 bytes captured (448 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50766, Dst Port: 8080, Seq: 0, Len: 0
No. Time Source Destination Protocol Length Info
5079 23.843738 127.0.0.1 127.0.0.1 TCP 108 8080 → 50766 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1
Frame 5079: 108 bytes on wire (864 bits), 56 bytes captured (448 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 8080, Dst Port: 50766, Seq: 0, Ack: 1, Len: 0
No. Time Source Destination Protocol Length Info
5080 23.843793 127.0.0.1 127.0.0.1 TCP 84 50766 → 8080 [ACK] Seq=1 Ack=1 Win=525568 Len=0
Frame 5080: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50766, Dst Port: 8080, Seq: 1, Ack: 1, Len: 0
No. Time Source Destination Protocol Length Info
5082 23.844179 127.0.0.1 127.0.0.1 HTTP 454 GET /ChatApp/chat/A HTTP/1.1
Frame 5082: 454 bytes on wire (3632 bits), 229 bytes captured (1832 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50766, Dst Port: 8080, Seq: 1, Ack: 1, Len: 185
Hypertext Transfer Protocol
No. Time Source Destination Protocol Length Info
5084 23.844213 127.0.0.1 127.0.0.1 TCP 84 8080 → 50766 [ACK] Seq=1 Ack=186 Win=525568 Len=0
Frame 5084: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 8080, Dst Port: 50766, Seq: 1, Ack: 186, Len: 0
No. Time Source Destination Protocol Length Info
5085 23.845363 127.0.0.1 127.0.0.1 HTTP 584 HTTP/1.1 101 Switching Protocols
Frame 5085: 584 bytes on wire (4672 bits), 294 bytes captured (2352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 8080, Dst Port: 50766, Seq: 1, Ack: 186, Len: 250
Hypertext Transfer Protocol
No. Time Source Destination Protocol Length Info
5086 23.845406 127.0.0.1 127.0.0.1 TCP 84 50766 → 8080 [ACK] Seq=186 Ack=251 Win=525312 Len=0
Frame 5086: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50766, Dst Port: 8080, Seq: 186, Ack: 251, Len: 0
No. Time Source Destination Protocol Length Info
5102 24.168567 127.0.0.1 127.0.0.1 WebSocket 212 WebSocket Text [FIN] [MASKED]
Frame 5102: 212 bytes on wire (1696 bits), 108 bytes captured (864 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50765, Dst Port: 8080, Seq: 186, Ack: 251, Len: 64
WebSocket
Line-based text data (1 lines)
No. Time Source Destination Protocol Length Info
5103 24.168606 127.0.0.1 127.0.0.1 WebSocket 212 WebSocket Text [FIN] [MASKED]
Frame 5103: 212 bytes on wire (1696 bits), 108 bytes captured (864 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50766, Dst Port: 8080, Seq: 186, Ack: 251, Len: 64
WebSocket
Line-based text data (1 lines)
No. Time Source Destination Protocol Length Info
5104 24.168610 127.0.0.1 127.0.0.1 TCP 84 8080 → 50765 [ACK] Seq=251 Ack=250 Win=525312 Len=0
Frame 5104: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 8080, Dst Port: 50765, Seq: 251, Ack: 250, Len: 0
No. Time Source Destination Protocol Length Info
5105 24.168648 127.0.0.1 127.0.0.1 TCP 84 8080 → 50766 [ACK] Seq=251 Ack=250 Win=525312 Len=0
Frame 5105: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 8080, Dst Port: 50766, Seq: 251, Ack: 250, Len: 0
No. Time Source Destination Protocol Length Info
5110 24.171796 127.0.0.1 127.0.0.1 WebSocket 110 WebSocket Text [FIN]
Frame 5110: 110 bytes on wire (880 bits), 57 bytes captured (456 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 8080, Dst Port: 50766, Seq: 251, Ack: 250, Len: 13
WebSocket
Line-based text data (1 lines)
No. Time Source Destination Protocol Length Info
5111 24.171827 127.0.0.1 127.0.0.1 TCP 84 50766 → 8080 [ACK] Seq=250 Ack=264 Win=525312 Len=0
Frame 5111: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50766, Dst Port: 8080, Seq: 250, Ack: 264, Len: 0
No. Time Source Destination Protocol Length Info
5112 24.172014 127.0.0.1 127.0.0.1 WebSocket 110 WebSocket Text [FIN]
Frame 5112: 110 bytes on wire (880 bits), 57 bytes captured (456 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 8080, Dst Port: 50765, Seq: 251, Ack: 250, Len: 13
WebSocket
Line-based text data (1 lines)
No. Time Source Destination Protocol Length Info
5113 24.172037 127.0.0.1 127.0.0.1 TCP 84 50765 → 8080 [ACK] Seq=250 Ack=264 Win=525312 Len=0
Frame 5113: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50765, Dst Port: 8080, Seq: 250, Ack: 264, Len: 0
No. Time Source Destination Protocol Length Info
5115 24.525813 127.0.0.1 127.0.0.1 TCP 84 50765 → 8080 [RST, ACK] Seq=250 Ack=264 Win=0 Len=0
Frame 5115: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50765, Dst Port: 8080, Seq: 250, Ack: 264, Len: 0
No. Time Source Destination Protocol Length Info
5118 24.562668 127.0.0.1 127.0.0.1 TCP 84 50766 → 8080 [RST, ACK] Seq=250 Ack=264 Win=0 Len=0
Frame 5118: 84 bytes on wire (672 bits), 44 bytes captured (352 bits) on interface 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50766, Dst Port: 8080, Seq: 250, Ack: 264, Len: 0
最后两个Wireshark条目显示客户端重置了连接(可能这就是服务器引发IOException
的原因)
这是我的客户端代码:
public class WebSocketClientEndpoint extends Endpoint {
private final String username;
private Session session;
public WebSocketClientEndpoint(final String username, final String URLString) throws URISyntaxException, IOException, DeploymentException {
this.username = username;
ContainerProvider.getWebSocketContainer().connectToServer(this, new URI(URLString));
}
@Override
public void onOpen(Session session, EndpointConfig endpointConfig) {
this.session = session;
// this.session.setMaxIdleTimeout(500L);
System.out.println("Connected to " + this.session.getId());
this.session.addMessageHandler((MessageHandler.Whole<String>) message -> {
ObjectMapper mapper = new ObjectMapper();
Map<String, String> map;
try {
map = mapper.readValue(message, new TypeReference<Map<String, String>>(){});
System.out.println(map.getOrDefault("message","NOTHING!!!"));
} catch (IOException e) {
e.printStackTrace();
}
});
}
@Override
public void onClose(Session session, CloseReason closeReason) {
super.onClose(session, closeReason);
System.out.println("this part executing");
System.out.println(session.getId() + " " + closeReason.getReasonPhrase());
}
@Override
public void onError(Session session, Throwable thr) {
System.out.println("Getting Errors here");
thr.printStackTrace();
}
public void sendMessage(String message, String destination) throws IOException {
if(this.session!=null) {
ObjectMapper mapper = new ObjectMapper();
HashMap<String,String> messageMap = new HashMap<>();
messageMap.put("username", this.username);
messageMap.put("destination",destination);
messageMap.put("message",message);
String payload = mapper.writeValueAsString(messageMap);
if (session.isOpen()) new Thread(() -> this.session.getAsyncRemote().sendText(payload)).start();
else System.out.println(session.getId() + " is closed");
}
else System.out.println("Send to whom?");
}
public void closeSession() throws IOException {
this.session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Normal closure"));
}
}
public static void main(String[] args) throws DeploymentException, IOException, URISyntaxException {
WebSocketClientEndpoint webSocketClientEndpoint1 = new WebSocketClientEndpoint("D","ws://localhost:8080/ChatApp/chat/D");
WebSocketClientEndpoint webSocketClientEndpoint2 = new WebSocketClientEndpoint("A","ws://localhost:8080/ChatApp/chat/A");
webSocketClientEndpoint1.sendMessage("From D to A", "A");
webSocketClientEndpoint2.sendMessage("From A to D", "D");
}
@ServerEndpoint(value = "/chat/{username}")
public class WebSocketServerEndpoint {
private static Map<String,Session> SESSION_MAP = Collections.synchronizedMap(new HashMap<>());
@OnOpen
public void handleOpen(Session session, @PathParam("username") String pathName) {
SESSION_MAP.putIfAbsent(pathName,session);
// session.getAsyncRemote().sendText(session + " " + pathName + " connected");
}
@OnMessage
public void handleMessage(String message, Session session) {
ObjectMapper mapper = new ObjectMapper();
Map<String,String> messageMap;
try {
messageMap = mapper.readValue(message, new TypeReference<Map<String, String>>(){});
String destination = messageMap.get("destination");
Session destinationSession = SESSION_MAP.get(destination);
if(destinationSession!=null)
destinationSession.getBasicRemote()
.sendText(messageMap.getOrDefault("message","NoMessageToSend"));
} catch (IOException e) {
e.printStackTrace();
}
}
@OnClose
public void handleClose(Session session, CloseReason closeReason) {
String username = session.getPathParameters().get("username");
SESSION_MAP.remove(username);
}
@OnError
public void handleError(Session session, Throwable thr) {
thr.printStackTrace();
}
}
现在的问题是,onMessage()
回调有时调用get,有时不调用。当它被调用时,会显示从A到B的消息,而从B到A的消息则不会显示。
为什么即使有两个不同的客户端,也会发生这种情况?不应该同时显示这两条消息吗。这两个客户端都是从同一个Java控制台应用程序模拟的
更新
我已经解决了只有一个客户端的消息被显示的问题,方法是每次消息传入时,在新线程上删除服务器上的消息处理(我后来更改了代码)。但仍然存在一个问题,即仍然存在只显示一个客户机消息的情况(尽管大约每4次执行一次)。
我想了解此类行为的原因您应该调查ClassCastException
。这导致了重置。@EJPClassCastException
完全是随机抛出的。服务器第一次启动(或重新启动)时,速率较低。错误来自OnError
方法。我还注意到服务器向客户端发回数据(显示在Wireshark中),但在客户端没有触发OnMessage
回调,之后,客户端重置连接,有时随机抛出ClassCastException
,在OnError
回调中捕获。OnError()
不会出现在堆栈跟踪中。OnError()
不会出现在堆栈跟踪中,但会从堆栈跟踪中抛出。我现在更新问题。我从使用编程端点切换到带注释的端点,ClassCastException
消失了,有时调用了OnMessage()
回调。
@ClientEndpoint
public class WebSocketClientEndpoint {
private final String username;
private Session session;
public WebSocketClientEndpoint(final String username, final String URLString) throws URISyntaxException, IOException, DeploymentException {
this.username = username;
ContainerProvider.getWebSocketContainer().connectToServer(this, new URI(URLString));
}
@OnOpen
public void handleOpen(Session session) {
this.session = session;
System.out.println("Connected to " + this.session.getId());
}
@OnMessage
public void handleMessage(String message) {
System.out.println("Executing Here in onMessage() callback");
System.out.println(message);
}
@OnClose
public void handleClose(Session session, CloseReason closeReason) {
System.out.println("this part executing");
System.out.println(session.getId() + " " + closeReason.getReasonPhrase());
}
@OnError
public void handleError(Session session, Throwable thr) {
System.out.println("Getting Errors here");
thr.printStackTrace();
}
public void sendMessage(String message, String destination) throws IOException {
if(this.session!=null) {
ObjectMapper mapper = new ObjectMapper();
HashMap<String,String> messageMap = new HashMap<>();
messageMap.put("username", this.username);
messageMap.put("destination",destination);
messageMap.put("message",message);
String payload = mapper.writeValueAsString(messageMap);
if (session.isOpen()) new Thread(() -> this.session.getAsyncRemote().sendText(payload)).start();
else System.out.println(session.getId() + " is closed");
}
else System.out.println("Send to whom?");
}
public void closeSession() throws IOException {
this.session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Normal closure"));
}
}