Java WebSocket客户端突然关闭连接

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.

我正在尝试使用WebSocket通过服务器模拟客户端到客户端的通信

这个想法是: 客户端A要向客户端B发送消息A向服务器发送消息,服务器通过查找会话映射来确定B是否有活动会话。然后服务器通过B的会话将消息转发到B

AB都能够连接到服务器,并能够将消息发送到服务器。但是服务器没有发回任何东西(没有触发
@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,有时不调用。当它被调用时,会显示从AB的消息,而从BA的消息则不会显示。
为什么即使有两个不同的客户端,也会发生这种情况?不应该同时显示这两条消息吗。这两个客户端都是从同一个Java控制台应用程序模拟的

更新
我已经解决了只有一个客户端的消息被显示的问题,方法是每次消息传入时,在新线程上删除服务器上的消息处理(我后来更改了代码)。但仍然存在一个问题,即仍然存在只显示一个客户机消息的情况(尽管大约每4次执行一次)。

我想了解此类行为的原因

您应该调查
ClassCastException
。这导致了重置。@EJP
ClassCastException
完全是随机抛出的。服务器第一次启动(或重新启动)时,速率较低。错误来自
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"));
    }
}