Java WebSocket客户端突然关闭连接

时间:2018-07-11 04:42:35

标签: java websocket wildfly java-websocket jsr356

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

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

A B 都能够连接到服务器,并且能够将消息发送到服务器。但是服务器没有发回任何东西(@OnMessage没有被触发)。在服务器端,我得到了这个:java.io.IOException: An existing connection was forcibly closed by the remote host
在客户端,我将这种情况放在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();
    }
}  

我首先尝试在Glassfish上运行它,但是没有任何正确的错误消息。然后,我在Wildfly上运行了它,并得到了IOException

我的问题是:

1。在我的实现上下文中,一个客户端如何通过使用WebSocket协议的服务器通过服务器与另一客户端对话?

2。我的实施中存在哪些问题?

更新

因此,我找出了ClassCastException的原因。我试图将纯字符串解析为JSON。我已修复它,这是我的新客户端端点:

@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"));
    }
}  

现在的问题是onMessage()回调有时会被调用,而有时不会被调用。当它被调用时,会显示从 A B 的消息,从 B A 的消息。不是。
即使有两个不同的客户端,为什么会发生这种情况?不应同时显示两条消息。这两个客户端都从同一Java控制台应用程序进行模拟。

更新
我已经解决了仅在显示一条消息时就出现的问题,方法是每次收到一条消息时就在新线程上删除服务器上的消息处理(我后来更改了代码)。但是仍然存在一个问题,那就是在某些情况下,仅显示一个客户端的消息(尽管大约有四次执行一次)。
我想了解这种行为的原因

0 个答案:

没有答案