SpringBoot集成websocket(5)|(使用OkHttpClient实现websocket以及详细介绍)

SpringBoot集成websocket(5)|(使用OkHttpClient实现websocket以及详细介绍)


章节
第一章链接: SpringBoot集成websocket(1)|(websocket客户端实现)
第二章链接: SpringBoot集成websocket(2)|(websocket服务端实现以及websocket中转实现)
第三章链接: SpringBoot集成websocket(3)|(websocket调用websocket采用回调方式实现数据互传)
第四章链接: SpringBoot集成websocket(4)|(使用okhttp3实现websocket)
第五章链接: SpringBoot集成websocket(5)|(使用OkHttpClient实现websocket以及详细介绍)

前言

上篇文章介绍了为什么选用OkHttpClient来实现websocket,本篇章就不过多的讲述,本章主要介绍OkHttpClient实现websocket多级代理跳转中的问题优化以及springboot实现websocket的一些常见问题。

一、初始化OkHttpClient

每个client对象都有自己的线程池和连接池,如果为每个请求都创建一个client对象,自然会出现内存溢出。所以官方建议OkHttpClient应该单例化,重用连接和线程能降低延迟和减少内存消耗。

1.OkHttpClient实现

官方介绍了三种创建client的方式
1、new OkHttpClient()
该方式将创建一个使用默认设置的client单例对象。
2、new OkHttpClient.Builder()
该方式允许自定义配置自己的单例client对象。配置connectionTimeout, readTimeout, writeTimeout等参数。
3、okHttpclient.newBuilder()
该方式通过已经存在的client对象,创建特殊需要的client对象。如 我们通过上个方法创建了自定义配置的单例client对象,但是针对某些场景需要调整某些参数,那么就需要使用该方法创建定制的client。新client对象与旧client对象共享连接池,线程池和其他配置。

    @Bean
    public OkHttpClient getOkHttpClient() {
   
        return new OkHttpClient.Builder()
                .connectTimeout(50L, TimeUnit.SECONDS)  // 超时连接时间
                .readTimeout(3*60L, TimeUnit.SECONDS)  // 超速读取时间
                .build();
    }

二、websocket服务代码实现

依赖上篇文章已经介绍过现在不做介绍

1.websocket服务端实现

springboot 服务端代码实现,用于给前端进行连接

@Component
@Data
@Slf4j
@ServerEndpoint(value = "/v1/chat")
public class DocChatServer {
   

    // 注意 此处定义的为静态变量,原因是ServerEndpoint 是多例的,不能用springBoo直接注入容器里的对象,static前提是变量都需要是单例,多例的话会有线程安全问题
    private static SparkClient4ChatBuild sparkClient4ChatBuild;
    private static OkHttpClient httpClient;
    @Autowired
    private void setOriginMessageSender(SparkClient4ChatBuild sparkClient4ChatBuild,OkHttpClient httpClient) {
   
        log.debug("客户端连接 A chat 初始化");
        this.sparkClient4ChatBuild = sparkClient4ChatBuild;
        this.httpClient = httpClient;
    }

    @OnOpen
    public void OnOpen(Session session) {
   
        log.debug("客户端连接 A chat 接口");
    }


    @OnClose
    public void OnClose() {
   
        log.debug("---客户端关闭 A chat 接口");
//        log.info("结束调用cancel");
//        planetClient4Chat.cancel();

    }

    @OnError
    public void onError(Session session, Throwable t) {
   
        log.debug("---客户端连接 A chat 接口异常");
        t.printStackTrace();
    }

    @OnMessage
    public void OnMessage(Session session, String message) {
   
        log.debug("客户端连接 A chat 进行中");
        boolean b = sendGptMessage(session, message);
        log.debug("客户端连接 A chat 结束:{}", b);
    }


    /**
     * 收到gpt型响应数据处理
     *
     * @param session 会话id
     * @return
     */
    private boolean sendGptMessage(Session session, String message) {
   
        SparkClient4Chat planetClient4Chat = sparkClient4ChatBuild.build();
        // 连接第三方ws地址
        planetClient4Chat.connect(new ApiResponseObserver() {
   
            public void onReceive(String message) {
   
                log.debug("收到响应数据:{}", message);
                JsonParse jsonMessage = JSON.parseObject(message).toJavaObject(JsonParse.class);
                if (jsonMessage.header.status == 2) {
   
                    try {
   
                        log.info("运行中调用cancel");
                        planetClient4Chat.cancel();
                    } catch (Exception e) {
   
                        throw new RuntimeException(e);
                    }
                }
            }
            public void onError(Throwable throwable) {
   
                log.debug("会话异常:{}", throwable.getMessage());
            }

            public void onCompleted() {
   
                log.error("回调收到结束");
            }
        });
        //String messages2 = "{\"讲一个故事\"}";
        planetClient4Chat.send(message);
        return true;
    }

}


注意:websocket 是多对象的,每个用户的聊天客户端对应 java 后台的一个 websocket 对象,前后台一对一(多对多)实时连接,所以 websocket 不可能像 servlet 一样做成单例的,让所有聊天用户连接到一个 websocket对象,这样无法保存所有用户的实时连接信息。可能 spring 开发者考虑到这个问题,没有让 spring 创建管理 websocket ,而是由 java 原来的机制管理websocket ,所以用户聊天时创建的 websocket 连接对象不是 spring 创建的,spring 也不会为不是他创建的对象进行依赖注入,所以如果不用static关键字,每个 websocket 对象的 service 都是 null

2.SparkClient4Chat 实现

用于处理第三方chat连接


@Slf4j
@Getter
@Setter
public class SparkClient4Chat {
   

    String chatUrl = "ws://xxx/v2.1/chat";
    private WebSocket webSocket;

    public void connect(OkHttpClient okHttpClient, ApiResponseObserver apiResponseObserver) {
   
        Request request = new Request.Builder().url(url).build();
        SparkChatServer sparkChatServer = new SparkChatServer(apiResponseObserver);
        this.webSocket = okHttpClient.newWebSocket(request, sparkChatServer);
    }

    public void send(String message) {
   
        log.debug("ApiRequest = {}", message);
        this.webSocket.send(message);
    }

    public void cancel() {
   
        log.debug("cancel begin...");
        if (this.webSocket != null) {
   
            this.webSocket.cancel();  // cancel暴力关闭(立马见效),用close是不能立马关闭的,管道中的数据还会持续发送过来
            this.webSocket = null;
            log.debug("cancel end.");
        }

    }

    public void close() throws Exception {
   
        log.debug("close begin...");
        if (this.webSocket != null) {
   
            log.debug("this.webSocket.close(1000, \"NORMAL_CLOSURE\")");
            this.webSocket.close(1000, "NORMAL_CLOSURE");
            this.webSocket = null;
            log.debug("close end...");
        }

    }
}

三、websocket客户端代码实现

主要用来连接第三方ws介绍

3.SparkChatServer实现

用于处理第三方chat连接 ,通过回调函数直接放回信息给客户端的连接


@Slf4j
public class SparkChatServer extends WebSocketListener {
   
    private ApiResponseObserver apiResponseObserver;

    public SparkChatServer(ApiResponseObserver apiResponseObserver) {
   
        this.apiResponseObserver = apiResponseObserver;
    }

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
   
        super.onOpen(webSocket, response);
        log.debug("连接GPT大模型");
    }

    @Override
    public void onMessage(WebSocket webSocket, String message) {
   
        apiResponseObserver.onReceive(message);
    }


    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
   
        apiResponseObserver.onError(t);
        log.error("chat连接出现异常:{}", t.getMessage());
    }
}

总结

本文主要介绍了为什么选用OkHttpClient来实现websocket,本篇章就不过多的讲述,本章主要介绍OkHttpClient实现websocket多级代理跳转中的问题优化以及springboot实现websocket的一些常见问题。

相关推荐

  1. SpringBoot集成WebSocket

    2023-12-16 13:04:03       47 阅读
  2. springboot +vue 集成websocket

    2023-12-16 13:04:03       31 阅读
  3. springboot 集成websocket

    2023-12-16 13:04:03       36 阅读
  4. Springboot 集成websocket

    2023-12-16 13:04:03       14 阅读
  5. SpringBoot集成websocket

    2023-12-16 13:04:03       11 阅读

最近更新

  1. MySQL中字段的实际长度

    2023-12-16 13:04:03       0 阅读
  2. 通过gateway 打印日志全局控制日志

    2023-12-16 13:04:03       0 阅读
  3. mysql实战入门-基础篇

    2023-12-16 13:04:03       0 阅读
  4. Linux安装Docker以及Docker Componse

    2023-12-16 13:04:03       0 阅读
  5. 通信技术在反无人机中的作用分析

    2023-12-16 13:04:03       0 阅读
  6. FastGPT源码部署,不使用docker

    2023-12-16 13:04:03       0 阅读
  7. 【ROS2】中级-编写动作服务器和客户端(Python)

    2023-12-16 13:04:03       1 阅读

热门阅读

  1. P1000 超级玛丽游戏

    2023-12-16 13:04:03       38 阅读
  2. 电商项目高并发缓存实践

    2023-12-16 13:04:03       30 阅读
  3. 屈臣氏中国销售业务转型

    2023-12-16 13:04:03       43 阅读
  4. 我的创作纪念日

    2023-12-16 13:04:03       48 阅读
  5. Kotlin 中的作用域函数

    2023-12-16 13:04:03       37 阅读
  6. 牛客后端开发面试题3

    2023-12-16 13:04:03       41 阅读
  7. 设计模式的应用——《职责链模式》

    2023-12-16 13:04:03       34 阅读
  8. react之useContext全局状态管理

    2023-12-16 13:04:03       46 阅读
  9. 软件测试面试中基础与功能的问题

    2023-12-16 13:04:03       35 阅读