WebSocket与Java原生通信

一、问题来源

一直以为WebSocket实现是在TCP协议层,直接可以用javascript的ws直接访问javaServerSocket进行通信。

  • java端代码

	private ServerSocket serverSocket;

	public void start(int port) throws IOException {
		serverSocket = new ServerSocket(port);
		System.out.println("server is running port " + port);
		while (true) {
			Socket sock = serverSocket.accept();
			System.out.println("connected from " + sock.getRemoteSocketAddress());
			new TcpClientHandler(sock).start();
		}
	}
  • JavaScript代码
    const socket = new WebSocket('ws://localhost:8888/')
    // Connection opened
    socket.addEventListener('open', function (event) {
        console.log('连接成功 ', event)
        socket.send('Hello Server!')
    })

java端能正常接受请求,但是却处理不了,同时js端报链接错误:从错误的日志来看,请求能到server端,但是没有握手成功,client接收不到请求。所以问题并不是那么简单,查阅了相关资料学习。

image.png

image.png

二、认识WebSocket

WebSocket是建立在TCP协议之上的应用层协议,并复用HTTP的握手通道,实现全双工通讯的网络技术。它支持双向通信。使用简单,只需要在浏览器中调用api就能完成协议切换。并支持扩展,可以在协议中实现自定义的子协议。相比http协议头部开销小,可以在网络中更快的传输。

相比TCP协议,WebSocket相对简单,只需要完成一次get请求,完成一次协议升级,这样就可以使用WebSocket通信。

image.png

连接过程:

ws://localhost:8888 发送get请求,请求协议转换,协议头:Connection:Upgrade Upgrade:websocket ,表示协议升级,升级协议到websocket。server端返回code 101代表,协议升级成功,后续通过双向通道传输数据即可。

image.png

三、示例代码

java原生代码,使用Java原生代码实现websocket服务的方法, 此方法需要引入一个第三方库java-websocket.jar

项目源代码位于: github.com/TooTallNate…

示例代码位于: github.com/TooTallNate…

如果你的项目使用gradle作为管理工具, 可以添加以下gradle依赖


implementation group: 'org.java-websocket', name: 'Java-WebSocket', version: '1.5.3'

如果你的项目使用maven进行管理, 可以添加以下maven依赖

mven依赖

<dependency>
    <groupId>org.java-websocket</groupId>
    <artifactId>Java-WebSocket</artifactId>
    <version>1.5.3</version>
</dependency>
package com.mum.socket;

import java.net.InetSocketAddress;
import java.net.UnknownHostException;

import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

public class SocketServer extends WebSocketServer {

	public SocketServer(int port) throws UnknownHostException {
		super(new InetSocketAddress(port));
	}

	public SocketServer(InetSocketAddress address) {
		super(address);
	}

	@Override
	public void onOpen(WebSocket conn, ClientHandshake handshake) {
		conn.send("Welcome to the server!"); // This method sends a message to the new client
		broadcast("new connection: " + handshake.getResourceDescriptor()); // This method sends a message to all clients
																			// connected
		System.out.println(conn.getRemoteSocketAddress().getAddress().getHostAddress() + " entered the room!");

	}

	@Override
	public void onClose(WebSocket conn, int code, String reason, boolean remote) {
		broadcast(conn + " has left the room!");
		System.out.println(conn + " has left the room!");

	}

	@Override
	public void onMessage(WebSocket conn, String message) {

		broadcast(message);
		System.out.println(conn + ": " + message);
	}

	@Override
	public void onError(WebSocket conn, Exception ex) {
		ex.printStackTrace();
		if (conn != null) {
			// some errors like port binding failed may not be assignable to a specific
			// websocket
		}

	}

	@Override
	public void onStart() {
		System.out.println("Server started!");
		//setConnectionLostTimeout(0);
		setConnectionLostTimeout(100);

	}

}

package com.mum.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class SocketServerTest {

	public static void main(String[] args) throws InterruptedException, IOException {
		int port = 8888; // 843 flash policy port

		SocketServer s = new SocketServer(port);
		s.start();
		System.out.println("ChatServer started on port: " + s.getPort());

		BufferedReader sysin = new BufferedReader(new InputStreamReader(System.in));
		while (true) {
			String in = sysin.readLine();
			s.broadcast(in);
			if (in.equals("exit")) {
				s.stop(1000);
				break;
			}
		}
	}
}

js代码实现

<!DOCTYPE html>
<html lang="zh-CN">
<header>
    <title>js code</title>
</header>
<style>
    .container {
        width: 100%;
        position: relative;
    }

    .margintLeft10 {
        margin-left: 10px;
    }
</style>

<body>
    <div class="container">
        <button class="margintLeft10" onclick="socketTest()">socketTest</button>
        <button class="margintLeft10" onclick="sendDate()">sendDate</button>

    </div>

    <script>
        let socket;

        function socketTest() {
            socket = new WebSocket('ws://localhost:8888/')

            // Connection opened
            socket.addEventListener('open', function (event) {
                console.log('连接成功 ', event)
                socket.send('Hello Server!')
            })

            // Listen for messages
            socket.addEventListener('message', function (event) {
                console.log('Message from server ', event.data)
            })

            // 监听错误事件
            socket.addEventListener('error', function (event) {
                console.log('error', event)
            })

            // 监听关闭事件
            socket.addEventListener('close', function (event) {
                console.log('close', event)
            })

        }

        function sendDate() {
            if (socket) {
                socket.send('现在时间: ' + new Date());
            } else {
                console.log('socket 未创建');
            }
        }
    </script>
   
</body>

</html>

node js实现更简单 借助 ws

const app = require("express")()
const server = require("http").Server(app)
const WebSocket = require("ws")
const MyWs = new WebSocket.Server({ port: 8080 })

MyWs.on("open", () => {
  console.log("connected")
})

MyWs.on("close", () => {
  console.log("disconnected")
})

MyWs.on("connection", (ws, req) => {
  const port = req.connection.remotePort
  const clientName = port
  console.log(`${clientName} is connected`)
  // 发送欢迎信息给客户端
  ws.send("Welcome :" + clientName + "加入聊天室")

  ws.on("message", (message) => {
    // 广播消息给所有客户端
    MyWs.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(clientName + " -> " + message)
      }
    })
  })
})
app.get("/", (req, res) => {
  res.sendfile(__dirname + "/index.html")
})

app.listen(8888)

参考资料


WebSocket:5分钟从入门到精通 juejin.cn/post/684490…

java实现websocket的五种方式 www.cnblogs.com/guoapeng/p/…

猜你喜欢

转载自juejin.im/post/7250377976134451257