最近在尝试仿造微信,用到了即时通讯这方面的知识,显然Http这种单向协议是不合适的,于是今天写一篇博客记录下WebSocket协议应用环境的搭建。

WebSocket概述

  WebSocket是一种全双工模式协议,只需一次握手就能建立长连接,双向传输数据;如果我用的是Http协议,作为客户端我只能去找服务端,而服务端不能来找我;而WebSocket则可以让客户端和服务端相互联系。

Http:

客户端:你好,我快递到了吗?(Ajax请求)
服务端:没到。
客户端:你好,我快递到了吗?(再发Ajax请求)
服务端:没到...
客户端:你好,我快递到了吗?(还发Ajax请求)
服务端:没到啊啊啊啊
。。。。。。

WebSocket:

客户端:你好,我快递到了吗?
服务端:没到。
服务端:那我留个电话给你,到了你打我电话哈(建立联系)
服务端:好
快递到了,服务端打电话给客户端✔

  大家看个乐,更严谨的还得看这里:WebSocket协议理解

服务端搭建

  好,那我们开始websocket的应用吧,首先我们来搭建服务端;

创建一个SpringBoot项目

  打开IDEA,选择File-> new-> project;选择Spring Initializr,如下图在Custom填入 https://start.aliyun.com/

  随便填填,选择war打包

Maven导入jar包

  打开pom文件,添加下列依赖:

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.75</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>

创建WebSocket配置类

  在 src\main\java\xx下 新建WebSocketConfig类:

@Component
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

创建WebSocket服务端类

  新建WebSocket类:

@Component
@ServerEndpoint(value = "/webSocket")
public class WebSocket {
    private Session session;
    private String userId;
    private static ConcurrentHashMap<String, WebSocket> webSocketMap = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        userId = session.getQueryString();
        webSocketMap.put(userId, this);
        System.out.println("新建连接,总数为" + webSocketSet.size());
    }

    @OnClose
    public void onClose(Session session) {
        webSocketMap.remove(userId);
        System.out.println("断开连接,总数为" + webSocketSet.size());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        //这里写你的消息处理逻辑
        sendMessage(JSONObject.parseObject(message,Message.class));
    }
    
    public void sendMessage(Message message) {
        try {
            webSocketMap.get(message.getTargetID())
                    .session.getBasicRemote()
                    .sendText(JSONObject.toJSONString(message));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  @ServerEndpoint(value = "/webSocket") 代表服务端的地址为:ws://localhost:8080/webSocket, 这里只给了服务端类的基本框架代码,你可以自行添加业务逻辑代码,我这里使用了自定义的Message类来包装消息;

客户端搭建

  为了体现客户端与服务端分离,我们另外创建一个Maven项目 IMTest,选择简单的maven-quickstart框架即可,在这里搭建客户端。

添加Maven依赖

  打开pom文件:

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.75</version>
    </dependency>

    <dependency>
        <groupId>org.java-websocket</groupId>
        <artifactId>Java-WebSocket</artifactId>
        <version>1.5.1</version>
    </dependency>

创建客户端类

  我们创建一个MyWebSocketClient类继承WebSocketClient类,并重写里面的方法:

public class MyWebSocketClient extends WebSocketClient {

    public MyWebSocketClient(URI serverUri) {
        super(serverUri);
    }

    public MyWebSocketClient(URI serverUri, Draft protocolDraft) {
        super(serverUri, protocolDraft);
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        System.out.println("连接成功");
    }

    @Override
    public void onMessage(String s) {
        //在这里写你自己的消息处理方式
        System.out.println("\n-------------------------");
        Message message = JSONObject.parseObject(s,Message.class);
        System.out.println(message.getDate() + "\n" + message.getSourceID() + ": " + message.getText());
        System.out.println("-------------------------");
    }

    @Override
    public void onMessage(ByteBuffer bytes) {
        super.onMessage(bytes);
    }

    @Override
    public void onClose(int i, String s, boolean b) {
        System.out.println("连接关闭");
    }

    @Override
    public void onError(Exception e) {
        System.out.println("连接错误!");
    }
}

测试

  我们来测试一下能否正常的运行:

  1. 运行服务端
  2. 在IMTest项目创建两个类:ClientTest和ClientTest2:
public class ClientTest {
    public static void main(String[] args) throws URISyntaxException, InterruptedException {
        MyWebSocketClient myClient = new MyWebSocketClient(new URI("ws://localhost:8080/webSocket?123"));
        myClient.connectBlocking();
        Scanner in = new Scanner(System.in);
        String str;
        while (true) {
            str = in.nextLine();
            Message msg = new Message("123", "456", str);
            myClient.send(JSONObject.toJSONString(msg));
        }
    }
}
//ClientTest2同理
  1. 运行ClientTest和ClientTest2,分别发送消息:


      成功!

应用

  到了这一步我们已经可以轻松的应用WebSocket来开发聊天、消息推送等功能了,同时这些在安卓也是可以同步的,比如:

  下次发一个山寨微信APP,安卓客户端的,食堂 冲冲冲!

2021/11/10更: 做出来了,但已弃坑客户端!

Q.E.D.


记录 • 分享 • 日常