Websocket——心跳檢測

1. 前言:為什么需要心跳機制?

????????在現代的實時網絡應用中,保持客戶端和服務端的連接穩定性是非常重要的。尤其是在長時間的網絡連接中,存在一些異常情況,導致服務端無法及時感知到客戶端的斷開,可能造成不必要的資源浪費,甚至是服務端的潛在錯誤。為了避免這種情況,我們需要一種機制來確保連接的有效性,這就是“心跳機制”。

心跳機制的必要性

????????心跳機制的作用在于周期性地檢測連接是否仍然活躍。簡單來說,心跳就像人類的心跳一樣,不斷“跳動”,如果在規定的時間內沒有收到心跳信號,服務端就可以判斷客戶端可能已經斷開連接,從而主動釋放資源或者做出其他處理。

異常斷開連接的場景

????????在正常情況下,前端和后端的連接斷開是可以通過調用相關方法來通知對方的。例如,當用戶關閉瀏覽器或者點擊“退出”按鈕時,前端可以主動向服務端發送斷開連接的請求,服務端也可以通過監聽斷開事件來進行清理工作。

????????然而,如果用戶的瀏覽器突然崩潰、網絡中斷或者關閉頁面時,前端無法發送斷開請求,服務端也無法及時感知到客戶端已經下線。在這種情況下,服務端就需要一個手段來周期性地檢查連接是否還存在。

服務端如何通過心跳保持客戶端狀態

????????為了應對這種情況,心跳機制便應運而生。心跳的基本原理是客戶端定時發送一個簡單的信號(通常是一個空的數據包)到服務端。服務端通過檢測這個信號是否按時到達來判斷客戶端是否仍然連接。如果在規定時間內沒有收到心跳包,服務端就認為該客戶端可能已經斷開,并可以主動關閉連接或執行其他操作。

????????Netty 作為一個高性能的網絡框架,內置了非常方便的心跳機制實現工具——IdleStateHandler。通過這個工具,開發者可以非常方便地設置心跳檢測的時間間隔,以及如何處理空閑狀態,從而確保網絡連接的健康和穩定。

小結

????????心跳機制在分布式應用、即時通訊、在線游戲等場景中是非常關鍵的,它幫助服務端及時發現并處理客戶端斷開的情況,避免資源的浪費和潛在的服務異常。接下來,我們將深入介紹 Netty 如何利用心跳機制來維持連接的穩定性。

2. Netty 心跳機制的實現原理

????????Netty 提供了 IdleStateHandler 組件,它是處理心跳機制的關鍵工具。這個處理器能夠幫助我們自動監測連接的空閑狀態,并且根據設定的時間間隔觸發心跳事件,從而幫助服務端檢測客戶端是否還保持連接。

2.1 IdleStateHandler 的作用

IdleStateHandler 是 Netty 提供的一個特殊的 ChannelHandler,主要作用是根據指定的時間,自動檢測連接的空閑狀態。它通過配置三個時間參數來定義空閑狀態:

  • readerIdleTime:如果在指定的時間內沒有讀取到數據,觸發空閑事件;
  • writerIdleTime:如果在指定的時間內沒有寫入數據,觸發空閑事件;
  • allIdleTime:如果在指定的時間內既沒有讀也沒有寫,觸發空閑事件。

通常情況下,我們會使用 readerIdleTime 來進行心跳檢測。也就是說,客戶端需要定期發送數據包(通常是心跳包)給服務端,確保在規定時間內,服務端能夠檢測到客戶端的活動。如果服務端在設定的時間內沒有收到心跳包,就會觸發相應的空閑事件(如 IdleStateEvent),然后服務端可以采取關閉連接等措施。

2.2 工作原理

Netty 的心跳機制的工作過程通常如下:

  1. 客戶端:每隔一定時間(如 10 秒),客戶端向服務端發送一個“心跳包”,該包通常是一個簡單的請求或一個空的數據包,目的是告訴服務端“我還活著”。
  2. 服務端:服務端在接收到客戶端的心跳包后,更新連接的活躍狀態,并且繼續等待客戶端的心跳信號。
  3. 超時檢測:如果在規定的時間(如 30 秒)內,服務端沒有收到客戶端的心跳包,就會觸發 IdleStateEvent,并根據配置的事件類型,執行相關的處理邏輯。
  4. 斷開連接:當服務端檢測到客戶端超過了心跳的最大空閑時間后,會主動斷開連接,釋放資源,避免無效連接占用資源。

2.3 Netty 實現步驟

通過 IdleStateHandler 實現心跳機制的步驟如下:

  1. 創建 IdleStateHandler:在管道(Pipeline)中添加 IdleStateHandler,并配置讀、寫或總空閑時間。
  2. 自定義事件處理器:當空閑時間觸發時,IdleStateHandler 會觸發 IdleStateEvent 事件,開發者可以通過自定義事件處理器來處理這些事件。
  3. 關閉連接:當空閑事件觸發時,服務端可以根據具體的業務邏輯決定是否關閉連接或執行其他操作。

2.4 IdleStateHandler 配置實例

????????假設我們希望每 30 秒檢測一次連接,如果 30 秒內沒有收到客戶端的數據(讀空閑),則認為該連接不再活躍,主動斷開連接。那么我們可以在 Netty 服務器的 ChannelPipeline 中這樣配置:

// 30秒內沒有讀數據即認為連接空閑,觸發讀空閑事件
pipeline.addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS));

在這里,30 表示如果在 30 秒內沒有接收到任何讀操作的數據包,Netty 會觸發一個 IdleStateEvent,而 0 表示我們不關心寫空閑和總空閑的狀態。

小結

????????通過 IdleStateHandler,Netty 提供了非常便捷的機制來處理心跳事件,確保服務端能夠及時發現客戶端是否斷開。接下來的部分,我們將更深入地探討如何自定義事件處理器,以及如何根據空閑事件的觸發來處理連接的關閉或其他業務邏輯。

3. 自定義處理空閑事件

????????在使用 IdleStateHandler 配置了心跳檢測后,我們需要編寫一個自定義的事件處理器來響應空閑事件的觸發。這個處理器將會監聽并處理由 IdleStateHandler 觸發的 IdleStateEvent,并根據實際需求采取相應的操作。

3.1 IdleStateEvent 介紹

IdleStateEvent 是 Netty 提供的一個事件對象,表示連接進入了空閑狀態。它由 IdleStateHandler 觸發,常見的事件類型有:

  • reader_idle:表示連接在指定的時間內沒有讀取到任何數據,即“讀取空閑”;
  • writer_idle:表示連接在指定的時間內沒有寫入任何數據,即“寫入空閑”;
  • all_idle:表示連接在指定的時間內既沒有讀也沒有寫,即“完全空閑”。

通常我們關心的主要是 reader_idle 類型的事件,因為我們希望通過客戶端定期發送心跳包,服務端來驗證連接是否活躍。

3.2 自定義事件處理器 NettyWebSocketServerHandler

????????接下來,我們編寫一個 NettyWebSocketServerHandler 類,來處理客戶端的請求并處理空閑事件。

public class NettyWebSocketServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// 這里可以處理業務邏輯,比如接收來自客戶端的數據包super.channelRead(ctx, msg);}@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {// 判斷是否是 IdleStateEvent 空閑事件if (evt instanceof IdleStateEvent) {IdleStateEvent event = (IdleStateEvent) evt;// 處理讀空閑事件if (event.state() == IdleState.READER_IDLE) {System.out.println("連接空閑,關閉連接:無數據讀取!");// 如果超時沒有讀數據,認為該連接斷開,關閉連接ctx.close();  // 關閉連接}}}
}

在上面的代碼中,我們實現了 userEventTriggered 方法來處理 IdleStateEvent 事件。當事件類型為 READER_IDLE(即讀取空閑事件)時,我們輸出日志并關閉連接。此時,服務端通過調用 ctx.close() 關閉連接,釋放相關資源。

3.3 將 NettyWebSocketServerHandler 添加到管道

????????在 Netty 服務器的 ChannelPipeline 中,添加自定義的 NettyWebSocketServerHandler 處理器,使得它能處理客戶端的空閑事件。

public class NettyWebSocketServer {public void start() throws InterruptedException {// 設置事件處理器鏈EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 用于接收客戶端連接EventLoopGroup workerGroup = new NioEventLoopGroup(); // 用于處理讀寫操作try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();// 添加空閑狀態檢測處理器,配置30秒沒有讀操作觸發事件pipeline.addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS));// 添加自定義的事件處理器來處理空閑事件pipeline.addLast(new NettyWebSocketServerHandler());}});// 綁定端口,啟動服務器b.bind(8090).sync().channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}

ChannelInitializer 中,我們首先添加了 IdleStateHandler,配置了讀空閑的時間為 30 秒。然后,我們添加了自定義的 NettyWebSocketServerHandler 來處理空閑事件。

3.4 處理空閑事件后進行用戶下線操作

????????除了關閉連接外,我們還可以在空閑事件發生時進行更復雜的操作,例如清理用戶會話、推送離線通知等。

????????假設我們有一個用戶管理的類來保存當前活躍的 WebSocket 連接,當連接空閑時,我們不僅關閉連接,還可以將該用戶從在線列表中移除。

public class UserManager {private static Map<String, Channel> activeUsers = new ConcurrentHashMap<>();public static void addUser(String userId, Channel channel) {activeUsers.put(userId, channel);}public static void removeUser(String userId) {activeUsers.remove(userId);}
}public class NettyWebSocketServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {if (evt instanceof IdleStateEvent) {IdleStateEvent event = (IdleStateEvent) evt;if (event.state() == IdleState.READER_IDLE) {// 這里假設可以通過 channel 獲取用戶的 IDString userId = (String) ctx.channel().attr(UserSession.USER_ID).get();System.out.println("用戶 " + userId + " 超時,關閉連接!");// 移除該用戶UserManager.removeUser(userId);// 關閉連接ctx.close();}}}
}

在這個修改版的 NettyWebSocketServerHandler 中,我們假設每個連接都有一個 userId,通過 channelattr 方法獲取用戶 ID,斷開連接時將該用戶從 UserManager 中移除。

小結

????????Netty 的心跳機制和空閑事件處理功能非常強大,它通過 IdleStateHandler 自動檢測連接的空閑狀態,幫助服務端發現和處理長時間不活動的客戶端連接。通過自定義的事件處理器,我們可以在空閑事件觸發時,進行連接關閉、資源清理、用戶下線等操作,確保服務器能夠及時響應并釋放資源。

4. 心跳機制的優化與擴展

????????在實現了基本的心跳檢測后,我們可以進一步對心跳機制進行優化和擴展。心跳機制的設計不僅僅是為了檢測連接是否存活,還可以用于其他優化,例如:

4.1 調整心跳時間間隔

????????默認情況下,我們在 Netty 服務器端設置了 IdleStateHandler(30, 0, 0),即 30 秒內沒有收到客戶端的消息,就會觸發 READER_IDLE 事件。但在實際應用中,我們可以根據業務需求調整心跳的頻率:

  • 如果服務器的負載較高,可以適當增加心跳間隔,例如 1 分鐘檢測一次,減少無用的心跳消息,降低服務器壓力。
  • 如果對在線狀態的準確性要求較高,可以縮短心跳間隔,例如 10~15 秒檢測一次,以便盡快發現連接異常。

心跳間隔需要根據實際業務進行權衡:間隔太短會增加服務器負擔,間隔太長可能會導致掉線檢測不及時

4.2 采用雙向心跳

????????目前我們的設計是 由客戶端定期發送心跳包,服務器被動檢測。但在一些場景下,例如 移動端網絡不穩定、瀏覽器休眠、弱網環境等,可能會導致客戶端心跳發送失敗或延遲。為此,我們可以采用 雙向心跳 機制,即:

  • 客戶端主動發送心跳(例如每 10 秒發送一次)。
  • 服務器也定期主動向客戶端發送心跳請求,如果客戶端在規定時間內沒有響應,則認為連接已斷開。

這樣可以 確保雙向通信的可靠性,避免單方面心跳導致的誤判。

4.3 結合 Redis 或數據庫存儲用戶在線狀態

????????在多服務器(集群)環境下,單個服務器維護的連接信息可能會不夠準確。例如,某個用戶可能已經斷線,但由于服務器沒有立即感知,導致用戶狀態仍然是“在線”。
為了解決這個問題,我們可以:

  • 將用戶的心跳時間存入 Redis,每次收到心跳更新 Redis 中的時間戳。
  • 其他服務器可以通過 Redis 檢測用戶是否長時間沒有發送心跳,從而更準確地判斷用戶在線狀態。

這樣,即使用戶的 WebSocket 連接在某個服務器上斷開了,整個系統仍然可以通過 Redis 統一管理用戶的在線狀態

4.4 結合 Netty 的自定義 ChannelHandler

除了 IdleStateHandler 之外,我們還可以自定義一個 HeartbeatHandler 來進行更加靈活的心跳控制。例如:

  • 記錄心跳次數,如果 連續 3 次心跳超時,才真正斷開連接,避免短暫的網絡抖動影響用戶體驗。
  • 結合 流量控制,如果服務器在高負載狀態下,可以適當放寬心跳檢測標準,防止誤判導致大規模掉線。

????????通過這些優化,我們可以讓 心跳機制更加智能、靈活、穩定,提高 WebSocket 連接的可靠性,為后續的即時通訊、推送等功能提供堅實的基礎。

5. 具體實現心跳檢測

????????在前面的介紹中,我們提到了 Netty 提供的 IdleStateHandler 組件,它可以幫助我們 檢測連接是否空閑。現在,我們來看它的 具體實現

5.1 服務器端的心跳檢測

????????在 NettyWebSocketServer 中,我們已經添加了 IdleStateHandler(30, 0, 0),即 如果 30 秒內沒有收到客戶端的消息,就會觸發 READER_IDLE 事件
但是,僅僅觸發事件是不夠的,我們還需要在 Handler 中監聽這個事件,并進行相應的處理。

步驟 1:繼承 SimpleChannelInboundHandler<TextWebSocketFrame>

我們需要自定義一個 NettyWebSocketServerHandler用于處理心跳事件WebSocket 消息

public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {if (evt instanceof IdleStateEvent) {IdleStateEvent event = (IdleStateEvent) evt;if (event.state() == IdleState.READER_IDLE) {System.out.println("【心跳超時】關閉連接:" + ctx.channel().remoteAddress());ctx.channel().close();}} else {super.userEventTriggered(ctx, evt);}}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {System.out.println("收到消息:" + msg.text());ctx.writeAndFlush(new TextWebSocketFrame("服務器已收到消息"));}
}

代碼解析

  1. 監聽 IdleStateEvent 事件

    • event.state() == IdleState.READER_IDLE 說明 30 秒內沒有收到消息,意味著客戶端可能已經斷線,我們就 手動關閉連接
  2. 處理正常的 WebSocket 消息

    • channelRead0 方法用于處理 客戶端發來的普通消息,這里簡單打印出來,并返回一個 確認消息

5.2 客戶端的心跳發送

????????為了防止服務器誤判掉線,客戶端需要定期發送心跳消息。
前端(JavaScript)可以這樣實現:

let socket = new WebSocket("ws://localhost:8090/ws");socket.onopen = function () {console.log("WebSocket 連接成功");setInterval(() => {if (socket.readyState === WebSocket.OPEN) {socket.send("ping");}}, 10000); // 每 10 秒發送一次心跳
};socket.onmessage = function (event) {console.log("收到服務器消息: " + event.data);
};socket.onclose = function () {console.log("WebSocket 連接關閉");
};

代碼解析

  1. 建立 WebSocket 連接,監聽 onopen 事件。
  2. 每 10 秒發送 "ping" 消息,保持連接活躍。
  3. 監聽服務器的 onmessage 事件,打印服務器返回的消息。
  4. 監聽 onclose 事件,一旦連接斷開,前端可以嘗試重新連接。

6. 服務器如何區分心跳和普通消息?

channelRead0 方法中,我們目前對所有消息都進行了打印和回寫。
但在實際應用中,我們需要 區分普通消息和心跳消息,避免誤處理:

@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {String text = msg.text();if ("ping".equals(text)) {System.out.println("收到客戶端心跳");ctx.writeAndFlush(new TextWebSocketFrame("pong")); // 返回心跳確認} else {System.out.println("收到普通消息:" + text);ctx.writeAndFlush(new TextWebSocketFrame("服務器已收到消息:" + text));}
}

改進點

  1. 如果收到 "ping",說明是 心跳消息,直接返回 "pong",避免誤處理。
  2. 如果收到普通消息,進行正常的邏輯處理。

7. 心跳機制測試

  1. 正常連接時

    • 前端每 10 秒發送 "ping",服務器返回 "pong",連接保持活躍。
  2. 如果前端關閉網頁

    • 服務器在 30 秒后觸發 READER_IDLE 事件,自動斷開連接。
  3. 如果網絡異常

    • 服務器仍然可以在 30 秒后感知到超時,并清理資源,保證不會有 無效連接 長時間占用服務器資源。

?????????這樣,我們就完成了 基于 Netty 的 WebSocket 心跳檢測,并且實現了 前端心跳發送、后端心跳檢測、心跳超時處理等功能

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/71735.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/71735.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/71735.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

tailwindcss 前端 css 框架 無需寫css 快速構建頁面

版本&#xff1a;VUE3 TS 框架 vite 文章中使用tailwindcss 版本&#xff1a; ^3.4.17 簡介&#xff1a; Tailwind CSS 一個CSS 框架&#xff0c;提供組件化的樣式&#xff0c;直接在HTML 中編寫樣式&#xff0c;無需額外自定義CSS &#xff0c;快速&#xff01; 簡潔&#…

MFC開發:如何創建第一個MFC應用程序

文章目錄 一、概述二、MFC 的主要組件三、創建一個MFC窗口四、控件綁定消息函數 一、概述 MFC 是微軟提供的一個 C 類庫&#xff0c;用于簡化 Windows 應用程序的開發。它封裝了 Windows API&#xff0c;提供面向對象的接口&#xff0c;幫助開發者更高效地創建圖形用戶界面&am…

【Git版本控制器】第四彈——分支管理,合并沖突,--no-ff,git stash

&#x1f381;個人主頁&#xff1a;我們的五年 &#x1f50d;系列專欄&#xff1a;Linux網絡編程 &#x1f337;追光的人&#xff0c;終會萬丈光芒 &#x1f389;歡迎大家點贊&#x1f44d;評論&#x1f4dd;收藏?文章 ? 相關筆記&#xff1a; https://blog.csdn.net/djd…

AI助力小微企業技術開發規范化管理 | 雜談

AI助力小微企業技術開發規范化管理 在小型技術研發企業中&#xff0c;人員配置緊張&#xff0c;往往一名員工需要承擔多項職務和任務。例如&#xff0c;后端程序開發人員可能同時要負責需求調研、數據庫設計、后端設計及開發&#xff0c;甚至在某些情況下還需兼任架構師的角色。…

SpringBoot+Vue+微信小程序的貓咖小程序平臺(程序+論文+講解+安裝+調試+售后)

感興趣的可以先收藏起來&#xff0c;還有大家在畢設選題&#xff0c;項目以及論文編寫等相關問題都可以給我留言咨詢&#xff0c;我會一一回復&#xff0c;希望幫助更多的人。 系統介紹 在當下這個高速發展的時代&#xff0c;網絡科技正以令人驚嘆的速度不斷迭代更新。從 5G …

DeepSeek提效實操革命,全場景應用指南 AI提示詞萬能公式四步法以及對話技巧

歡迎來到濤濤聊AI DeepSeek系列文章 三塊顯示器如何擺放效率最高&#xff0c;讓deepseek給深度思考下 阿里云免費試用 DeepSeek大模型。 限時送 100 萬 tokens&#xff0c;快來搶先免費體驗&#xff01;AI 助手不再出現系統繁忙阿里云免費試用 DeepSeek大模型。 限時送 100 萬 …

智慧教室與無紙化同屏技術方案探討與實現探究

引言 隨著教育信息化的不斷發展&#xff0c;智慧教室和無紙化同屏技術逐漸成為提升教學效率和質量的重要手段。大牛直播SDK憑借其強大的音視頻處理能力和豐富的功能特性&#xff0c;在智慧教室和無紙化同屏領域積累了眾多成功案例。本文將深入探討基于大牛直播SDK的智慧教室、…

Linux MySQL 8.0.29 忽略表名大小寫配置

Linux MySQL 8.0.29 忽略表名大小寫配置 問題背景解決方案遇到的問題&#xff1a; 問題背景 突然發現有個大寫的表報不存在。 在Windows上&#xff0c;MySQL是默認支持忽略大小寫的。 這個時候你要查詢一下是不是沒有配置&#xff1a; SHOW VARIABLES LIKE lower_case_table…

【藍橋杯單片機】第十三屆省賽第二場

一、真題 二、模塊構建 1.編寫初始化函數(init.c) void Cls_Peripheral(void); 關閉led led對應的鎖存器由Y4C控制關閉蜂鳴器和繼電器 2.編寫LED函數&#xff08;led.c&#xff09; void Led_Disp(unsigned char ucLed); 將ucLed取反的值賦給P0 開啟鎖存器 關閉鎖存…

【CMake 教程】常用函數與構建案例解析(三)

一、CMake 常用函數簡析 1. 條件判斷 if() / elseif() / else() 在 CMake 腳本中&#xff0c;條件判斷是控制邏輯的重要工具。if() 支持多種比較語句&#xff0c;包括數值、字符串、布爾值和變量存在性等。在條件滿足時執行特定邏輯代碼&#xff0c;下面是典型語法&#xff1…

ASP.NET Core 8.0學習筆記(二十七)——數據遷移:Migrations深入與其他遷移命令

一、數據庫架構的管理 1.EF Core提供兩種方式來保持EF Core的模型與數據庫保持同步。 (1)以數據庫為準&#xff1a;反向工程&#xff08;Db First&#xff09;&#xff0c;適用于中大型工程 (2)以代碼為準&#xff1a;數據遷移&#xff08;Code First&#xff09;&#xff0c;…

Python 基本語法的詳細解釋

目錄 &#xff08;1&#xff09;注釋 &#xff08;2&#xff09;縮進 &#xff08;3&#xff09;變量和數據類型 變量定義 數據類型 &#xff08;4&#xff09;輸入和輸出 輸出&#xff1a;print() 函數 輸入&#xff1a;input() 函數 &#xff08;1&#xff09;注釋 注…

20-R 繪圖 - 餅圖

R 繪圖 - 餅圖 R 語言提供來大量的庫來實現繪圖功能。 餅圖&#xff0c;或稱餅狀圖&#xff0c;是一個劃分為幾個扇形的圓形統計圖表&#xff0c;用于描述量、頻率或百分比之間的相對關系。 R 語言使用 pie() 函數來實現餅圖&#xff0c;語法格式如下&#xff1a; pie(x, l…

Ubuntu 22.04 一鍵部署MinerU1.1.0

MinerU MinerU是一款將PDF轉化為機器可讀格式的工具&#xff08;如markdown、json&#xff09;&#xff0c;可以很方便地抽取為任意格式。 MinerU誕生于書生-浦語的預訓練過程中&#xff0c;我們將會集中精力解決科技文獻中的符號轉化問題&#xff0c;希望在大模型時代為科技發…

紫光同創開發板使用教程(二):sbit文件下載

sbit文件相當于zynq里面的bit文件&#xff0c;紫光的fpga工程編譯完成后會自動生成sbit文件&#xff0c;因工程編譯比較簡單&#xff0c;這里不在講解工程編譯&#xff0c;所以我這里直接下載sbit文件。 1.工程編譯完成后&#xff0c;可以看到Flow列表里面沒有報錯&#xff0c…

DeepSeek 部署全指南:常見問題解析與最新技術實踐

引言 隨著開源大模型DeepSeek的爆火&#xff0c;其部署需求激增&#xff0c;但用戶在實際操作中常面臨服務器壓力、本地部署性能瓶頸、API配置復雜等問題。本文結合2025年最新技術動態&#xff0c;系統梳理DeepSeek部署的核心問題與解決方案&#xff0c;并分享行業實踐案例&am…

Vue02

Vue02 綁定class樣式 字符串寫法&#xff0c;適用于&#xff1a;樣式的類名不確定&#xff0c;需要動態指定 數組寫法&#xff0c;適用于&#xff1a;要綁定的樣式個數不確定&#xff0c;名字也不確定 對象寫法&#xff0c;適用于&#xff1a;要綁定的樣式個數缺點&#xff…

超導量子計算機的最新進展:走向實用化的量子革命

超導量子計算機的最新進展:走向實用化的量子革命 大家好,我是 Echo_Wish,今天我們來聊聊科技圈最炙手可熱的話題之一——超導量子計算機。近年來,量子計算領域可謂是風起云涌,而超導量子計算機作為主流路線之一,已經在學術界和工業界取得了不少突破性進展。 那么,超導…

LangChain構建行業知識庫實踐:從架構設計到生產部署全指南

文章目錄 引言:行業知識庫的進化挑戰一、系統架構設計1.1 核心組件拓撲1.2 模塊化設計原則二、關鍵技術實現2.1 文檔預處理流水線2.2 混合檢索增強三、領域適配優化3.1 醫學知識圖譜融合3.2 檢索結果重排序算法四、生產環境部署4.1 性能優化方案4.2 安全防護體系五、評估與調優…

Node.js中如何修改全局變量的幾種方式

Node.js中如何修改全局變量。我需要先理解他們的需求。可能他們是在開發過程中遇到了需要跨模塊共享數據的情況&#xff0c;或者想要配置一些全局可訪問的設置。不過&#xff0c;使用全局變量可能存在一些問題&#xff0c;比如命名沖突、難以維護和測試困難&#xff0c;所以我得…