Websocket握手在Java中失败

所以,我正在尝试解析一个使用websocket向客户端发送数据的网站。 从我读过的内容:

  • 链接1
  • 链接2

我知道,为了创建连接,我需要向服务器发送一个特殊的http请求,然后我将检索一些用于访问该通道的数据。

我做了什么:

  • 创建了http请求

    `URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); // optional default is GET con.setRequestMethod("GET"); //add request header con.setRequestProperty("Cache-Control", "no-cache"); con.setRequestProperty("Host", "www.example.com"); con.setRequestProperty("Upgrade", "websocket"); con.setRequestProperty("Connection", "upgrade"); con.setRequestProperty("Origin", "https://example.com"); con.setRequestProperty("Sec-WebSocket-Extensions", "x-webkit-deflate-frame"); con.setRequestProperty("Sec-WebSocket-Key", "QkWkChtTGpaZL5PkOMaRtg=="); con.setRequestProperty("Sec-WebSocket-Version", "13"); con.setRequestProperty("User-Agent", "Mozilla/..; 

    `

我用代码200(不应该是101)读取响应。

问题:

  1. 我如何生成Sec-Websocket-Key? (例如从firebug中获取,实际上所有头文件)

1.1。 还有什么可以做的?

1.2。 必须使用http中的相同链接来访问websocket? 只用wss而不是https?

  • 在此之后,我尝试将客户端连接到服务器并在onMessage方法中接收消息。

    WebSocketContainer container = ContainerProvider.getWebSocketContainer(); Session session = container.connectToServer(ClientEndpoint.class, buildCEC(), new URI("wss://async.example.com/socket.io/1/?t=" + System.currentTimeMillis()));

  • 我尝试在buildCec()中插入标题以连接到服务器。 ClientEndpointConfig config = ClientEndpointConfig.Builder.create().build(); Configurator conf = config.getConfigurator();

     `Map<String, List> headers = new HashMap<String, List>(); headers.put("Connection", Arrays.asList("keep-alive", "Upgrade")); headers.put("Sec-Websocket-Extensions", Arrays.asList("x-webkit-deflate-frame")); headers.put("Sec-Websocket-key", Arrays.asList("cx36sHrtuW9HZAaB6kKa/Q==")); headers.put("Sec-Websocket-Version", Arrays.asList("13")); headers.put("Upgrade", Arrays.asList("websocket")); headers.put("User-Agent", Arrays.asList("Mozill...")); conf.beforeRequest(headers); return config;` 

问题

  1. 我的判断是好的,以防我解决并从http升级请求中收到101状态代码?(我的意思是,我接下来要做的是什么细节?)
  2. 请不要评判我,我刚开始使用java中的websockets,我不太了解javascript,我想用jsr-356在纯java中做这个客户端。 我用websockets做了一些小例子,但我找不到一个好的客户端,有标题和更复杂的握手。
  3. 是否可以连接到未知服务器,不知道所有细节?

我正在使用一个编程端点并导入javax.websocket.ContainerProvider; 用于处理来自jsr356的websocket连接。

这里有很多主题。

  1. 不要将URLHttpConnection用于WebSocket,它根据HTTP语义管理输出/输入流,不处理升级连接。 使用标准sockets。
  2. 阅读RFC-6455:WebSocket协议
  3. 在RFC6455中多次提到Sec-WebSocket-Key ,它有1个总体目的,客户端可以certificate它从服务器接收到有效的WebSocket打开握手 。 客户端有规则,服务器端有关于它应该做什么的规则,以及它应该如何响应它。 (简而言之,它是客户端选择的随机值,发送到服务器,服务器在此步骤的RFC指定GUID上计算,计算SHA-1哈希,并在其自己的Sec-WebSocket-Key使用此哈希进行响应,客户端validation以确认服务器是否真的支持WebSocket)
  4. 阅读第5.2节。 基本框架协议仔细,特别是3种有效负载长度的部分(你必须实现对所有3的支持,因为服务器需要规则来validation这一点)’ – 请参阅其他答案 – Java Websocket Text Frame Error > = 128?
  5. 至于javax.websocket.server.ServerEndpointConfig.Configurator ,您无法调用这些方法。 这些是在建立连接的过程中由JSR-356 websocket服务器实现调用的。 请参阅我关于此过程的其他答案 – 在Web Socket @ServerEndpoint中从HttpServletRequest访问HttpSession
  6. 请注意框架validation规则 – 如何在Java中解析和validationWebSocket框架?

我知道有几个JSR-356独立客户端。

  • Eclipse Jetty 9.1+
   org.eclipse.jetty.websocket javax-websocket-client-impl 9.1.0.v20131115  
  • Apache Tomcat 8.0+
   org.apache.tomcat tomcat-websocket 8.0.0-RC5   org.apache.tomcat tomcat-coyote 8.0.0-RC5  
  • 灰熊计划
   org.glassfish.grizzly grizzly-websockets 2.3.8  
  • Glassfish Tyrus
   org.glassfish.tyrus.bundles tyrus-standalone-client 1.3.3  

如果您确实编写了自己的WebSocket客户端,请确保您针对Autobahn WebSocket Protocol Testsuite进行测试(每个人都针对此测试套件编写实现测试,它有点成为事实上的协议validation套件)

我想这就是你需要的:

  String secAccept = sha1base64(secKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); private String sha1base64(String str) { MessageDigest md = null; try { md = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return Base64.encode(md.digest(str.getBytes())); }