Java游戲服務器開發流水賬(7)網絡通信簡介

在 Java 游戲服務器開發中,網絡通訊是核心組成部分,它主要負責客戶端與服務器之間的數據交換。

一、網絡通訊基礎

1. 網絡模型
  • C/S 架構:游戲服務器采用客戶端 / 服務器模式,客戶端向服務器發送請求,服務器處理請求并返回響應。
  • B/S 架構:部分網頁游戲采用瀏覽器 / 服務器模式,但實時性要求高的游戲通常不采用這種架構。
2. 通訊協議
  • TCP:面向連接的可靠協議,保證數據按序到達,適合需要可靠傳輸的場景,如 MMORPG。
  • UDP:無連接的不可靠協議,不保證數據順序和完整性,但延遲低,適合實時性要求高的游戲,如 FPS。
  • HTTP/HTTPS:常用于游戲中的非實時通信,如登錄驗證、數據同步等。
3. 數據格式
  • 文本協議:如 JSON、XML,易于調試但效率較低。
  • 二進制協議:如 Protobuf、MessagePack,效率高,適合高性能服務器。
  • 自定義協議:根據游戲需求設計的專用協議,通常是二進制格式。

二、Java 網絡編程 API

Java 提供了多種網絡編程 API,適用于不同的應用場景:

1. 傳統的阻塞 IO (BIO)
  • ServerSocket/Socket:基于線程池實現多客戶端連接,每個連接占用一個線程。
  • 缺點:線程開銷大,不適合高并發場景。
2. 非阻塞 IO (NIO)
  • Selector/Channel:單線程管理多個連接,基于事件驅動,適合高并發場景。
  • 缺點:編程模型復雜,需要處理各種狀態。
3. 異步 IO (AIO)
  • AsynchronousServerSocketChannel/AsynchronousSocketChannel:基于回調機制,真正的異步非阻塞,適合長連接、高并發場景。
  • 優點:線程利用率高,編程模型相對簡單。
4. 高性能網絡框架
  • Netty:基于 NIO 的高性能網絡框架,簡化了網絡編程,廣泛應用于游戲服務器開發。
  • Mina:類似 Netty 的網絡框架,提供了簡單易用的 API。

三、Java AIO 網絡通訊實現原理

在前面提供的示例中,我們使用了 Java AIO 實現游戲服務器的網絡通訊。下面詳細解釋其工作原理:

1. 服務器端核心組件
  • AsynchronousChannelGroup:線程池管理,負責處理 IO 操作和回調任務。
  • AsynchronousServerSocketChannel:異步服務器套接字通道,用于監聽客戶端連接。
  • AsynchronousSocketChannel:異步套接字通道,用于與客戶端進行數據交換。
  • CompletionHandler:回調接口,處理 IO 操作完成后的邏輯。
2. 連接建立流程
  1. 創建線程池和服務器通道

    ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
    group = AsynchronousChannelGroup.withThreadPool(executor);
    serverChannel = AsynchronousServerSocketChannel.open(group).bind(new InetSocketAddress(port));
    
  2. 接受客戶端連接

    serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {@Overridepublic void completed(AsynchronousSocketChannel client, Void attachment) {// 處理新連接acceptConnections(); // 繼續接受下一個連接}
    });
    
3. 數據讀寫流程
  • 讀取數據

    channel.read(readBuffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesRead, Void attachment) {// 處理讀取到的數據read(); // 繼續讀取下一次數據}
    });
    
  • 寫入數據

    channel.write(writeBuffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesWritten, Void attachment) {// 繼續寫入剩余數據if (writeBuffer.hasRemaining()) {channel.write(writeBuffer, null, this);}}
    });
    
4. 異步回調機制

Java AIO 的核心是異步回調機制:

  • 當 IO 操作完成時(如連接建立、數據讀取),會觸發相應的 CompletionHandler 回調方法。
  • 回調方法在 AsynchronousChannelGroup 的線程池中執行,不會阻塞發起 IO 操作的線程。
  • 這種機制使得一個線程可以處理多個客戶端連接,大大提高了服務器的并發處理能力。

四、游戲服務器網絡優化策略

1. 減少網絡延遲
  • 使用 UDP 協議:對于實時性要求高的游戲,如動作游戲、競技游戲,考慮使用 UDP 協議。
  • 優化服務器位置:將服務器部署在離玩家近的地理位置,減少物理距離造成的延遲。
  • 預測與補償算法:在客戶端實現預測算法,減少玩家操作的感知延遲。
2. 提高吞吐量
  • 使用高性能網絡框架:如 Netty,它提供了更好的性能和更簡單的編程模型。
  • 優化線程池配置:根據服務器硬件和業務特點調整線程池大小。
  • 采用對象池技術:減少內存分配和垃圾回收開銷。
3. 降低帶寬消耗
  • 壓縮數據:對發送的數據進行壓縮,如使用 Zlib、Snappy 等壓縮算法。
  • 減少不必要的數據包:只發送必要的數據,避免冗余信息。
  • 使用增量更新:只發送變化的數據,而不是整個狀態。
4. 增強可靠性
  • 實現可靠 UDP:在 UDP 協議之上實現可靠性保證,如確認機制、重傳機制。
  • 心跳機制:定期發送心跳包,檢測連接狀態。
  • 斷線重連:實現客戶端斷線重連功能,保持游戲狀態。

五、安全與性能監控

1. 網絡安全
  • 防止 DDOS 攻擊:使用防火墻、流量過濾等技術防御 DDOS 攻擊。
  • 數據加密:對敏感數據進行加密傳輸,如登錄信息、支付信息。
  • 協議驗證:驗證客戶端發送的數據包格式和內容,防止惡意攻擊。
2. 性能監控
  • 連接數監控:監控當前連接數,防止過多連接導致服務器崩潰。
  • 流量監控:監控網絡流量,及時發現異常流量。
  • 響應時間監控:監控服務器響應時間,及時發現性能瓶頸。

六、簡單的源碼

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;public class GameClient {private final String host;private final int port;private AsynchronousSocketChannel channel;private final ByteBuffer readBuffer = ByteBuffer.allocate(1024);private final Scanner scanner = new Scanner(System.in);public GameClient(String host, int port) {this.host = host;this.port = port;}public void start() throws IOException {// 打開客戶端通道channel = AsynchronousSocketChannel.open();// 連接到服務器channel.connect(new InetSocketAddress(host, port), null, new CompletionHandler<Void, Void>() {@Overridepublic void completed(Void result, Void attachment) {System.out.println("已連接到服務器: " + host + ":" + port);// 開始讀取服務器消息read();// 啟動用戶輸入處理線程new Thread(GameClient.this::handleUserInput).start();}@Overridepublic void failed(Throwable exc, Void attachment) {System.err.println("連接服務器失敗: " + exc.getMessage());}});}private void read() {readBuffer.clear();channel.read(readBuffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesRead, Void attachment) {if (bytesRead == -1) {// 服務器關閉了連接System.out.println("服務器斷開連接");close();return;}readBuffer.flip();byte[] data = new byte[bytesRead];readBuffer.get(data);String message = new String(data, StandardCharsets.UTF_8);// 顯示服務器消息System.out.print("\r" + message);System.out.print("> ");// 繼續讀取read();}@Overridepublic void failed(Throwable exc, Void attachment) {System.err.println("讀取消息失敗: " + exc.getMessage());close();}});}private void handleUserInput() {BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));try {while (channel.isOpen()) {System.out.print("> ");String message = reader.readLine();if (message == null || message.equalsIgnoreCase("/exit")) {close();break;}sendMessage(message);}} catch (IOException e) {System.err.println("讀取用戶輸入失敗: " + e.getMessage());close();}}private void sendMessage(String message) {ByteBuffer buffer = ByteBuffer.wrap((message + "\n").getBytes(StandardCharsets.UTF_8));channel.write(buffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesWritten, Void attachment) {// 繼續寫入剩余數據,如果有的話if (buffer.hasRemaining()) {channel.write(buffer, null, this);}}@Overridepublic void failed(Throwable exc, Void attachment) {System.err.println("發送消息失敗: " + exc.getMessage());close();}});}public void close() {try {if (channel.isOpen()) {channel.close();System.out.println("客戶端已關閉");}} catch (IOException e) {System.err.println("關閉客戶端失敗: " + e.getMessage());}}public static void main(String[] args) {GameClient client = new GameClient("localhost", 8080);try {client.start();// 保持主線程運行Thread.currentThread().join();} catch (IOException | InterruptedException e) {e.printStackTrace();client.close();}}
}    
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class GameServer {private final int port;private AsynchronousChannelGroup group;private AsynchronousServerSocketChannel serverChannel;private final Map<String, PlayerSession> sessions = new HashMap<>();public GameServer(int port) {this.port = port;}public void start() throws IOException {// 創建線程池ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);group = AsynchronousChannelGroup.withThreadPool(executor);// 打開服務器通道serverChannel = AsynchronousServerSocketChannel.open(group).bind(new InetSocketAddress(port));System.out.println("游戲服務器啟動,監聽端口: " + port);// 開始接受連接acceptConnections();}private void acceptConnections() {serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {@Overridepublic void completed(AsynchronousSocketChannel client, Void attachment) {// 繼續接受下一個連接acceptConnections();// 處理新連接handleNewConnection(client);}@Overridepublic void failed(Throwable exc, Void attachment) {System.err.println("接受連接失敗: " + exc.getMessage());}});}private void handleNewConnection(AsynchronousSocketChannel client) {try {String sessionId = UUID.randomUUID().toString();PlayerSession session = new PlayerSession(sessionId, client, this);// 存儲會話sessions.put(sessionId, session);System.out.println("新玩家連接: " + sessionId + " 來自 " + client.getRemoteAddress());// 開始讀取客戶端消息session.read();// 發送歡迎消息session.send("歡迎加入游戲服務器! 您的ID: " + sessionId);} catch (IOException e) {System.err.println("處理新連接失敗: " + e.getMessage());try {client.close();} catch (IOException ex) {ex.printStackTrace();}}}public void broadcast(String message, String excludeSessionId) {for (PlayerSession session : sessions.values()) {if (!session.getSessionId().equals(excludeSessionId)) {session.send(message);}}}public void removeSession(String sessionId) {sessions.remove(sessionId);System.out.println("玩家斷開連接: " + sessionId);}public void stop() {try {// 關閉所有會話for (PlayerSession session : sessions.values()) {session.close();}// 關閉服務器通道和組if (serverChannel != null && serverChannel.isOpen()) {serverChannel.close();}if (group != null && !group.isShutdown()) {group.shutdownNow();}System.out.println("游戲服務器已停止");} catch (IOException e) {System.err.println("停止服務器失敗: " + e.getMessage());}}public static void main(String[] args) {GameServer server = new GameServer(8080);try {server.start();// 讓服務器保持運行Thread.currentThread().join();} catch (IOException | InterruptedException e) {e.printStackTrace();server.stop();}}
}    
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;public class PlayerSession {private final String sessionId;private final AsynchronousSocketChannel channel;private final GameServer server;private final ByteBuffer readBuffer = ByteBuffer.allocate(1024);private final ByteBuffer writeBuffer = ByteBuffer.allocate(1024);// 玩家狀態private String username;private int x, y;private boolean isLoggedIn = false;public PlayerSession(String sessionId, AsynchronousSocketChannel channel, GameServer server) {this.sessionId = sessionId;this.channel = channel;this.server = server;}public String getSessionId() {return sessionId;}public void read() {readBuffer.clear();channel.read(readBuffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesRead, Void attachment) {if (bytesRead == -1) {// 客戶端關閉了連接close();return;}readBuffer.flip();byte[] data = new byte[bytesRead];readBuffer.get(data);String message = new String(data, StandardCharsets.UTF_8).trim();// 處理消息handleMessage(message);// 繼續讀取read();}@Overridepublic void failed(Throwable exc, Void attachment) {System.err.println("讀取消息失敗: " + exc.getMessage());close();}});}private void handleMessage(String message) {System.out.println("收到來自 " + sessionId + " 的消息: " + message);// 簡單的命令處理if (message.startsWith("/login ")) {handleLogin(message.substring(7));} else if (message.startsWith("/move ")) {handleMove(message.substring(6));} else if (message.equals("/logout")) {handleLogout();} else if (message.equals("/players")) {sendPlayerList();} else {// 廣播消息給其他玩家if (isLoggedIn) {server.broadcast("[" + username + "] " + message, sessionId);} else {send("請先登錄 /login <用戶名>");}}}private void handleLogin(String username) {if (isLoggedIn) {send("您已經登錄為 " + this.username);return;}this.username = username;this.isLoggedIn = true;this.x = 0;this.y = 0;send("登錄成功,歡迎 " + username);server.broadcast(username + " 加入了游戲", sessionId);}private void handleMove(String direction) {if (!isLoggedIn) {send("請先登錄 /login <用戶名>");return;}switch (direction.toLowerCase()) {case "up": y--; break;case "down": y++; break;case "left": x--; break;case "right": x++; break;default: send("無效的移動方向: " + direction);return;}send("您移動到了位置 (" + x + ", " + y + ")");server.broadcast(username + " 移動到了位置 (" + x + ", " + y + ")", sessionId);}private void handleLogout() {if (!isLoggedIn) {send("您尚未登錄");return;}server.broadcast(username + " 離開了游戲", sessionId);this.isLoggedIn = false;send("您已登出");}private void sendPlayerList() {StringBuilder builder = new StringBuilder("在線玩家列表:\n");// 實際應用中應該遍歷所有玩家并添加到列表builder.append(username).append(" (").append(x).append(", ").append(y).append(")\n");send(builder.toString());}public void send(String message) {writeBuffer.clear();writeBuffer.put((message + "\n").getBytes(StandardCharsets.UTF_8));writeBuffer.flip();channel.write(writeBuffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesWritten, Void attachment) {// 繼續寫入剩余數據,如果有的話if (writeBuffer.hasRemaining()) {channel.write(writeBuffer, null, this);}}@Overridepublic void failed(Throwable exc, Void attachment) {System.err.println("發送消息失敗: " + exc.getMessage());close();}});}public void close() {try {if (channel.isOpen()) {channel.close();server.removeSession(sessionId);}} catch (IOException e) {System.err.println("關閉會話失敗: " + e.getMessage());}}
}    

六、總結

雖然AIO 提供了高效的異步非阻塞編程模型,適合開發高性能的游戲服務器。但是手擼Java 游戲服務器的網絡通訊相對比較復雜,需要綜合考慮性能、可靠性、安全性等多個方面。上面的代碼是最簡單的實現

在實際開發中,通常會使用成熟的網絡框架如 Netty,以簡化開發流程并提高系統穩定性。

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

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

相關文章

使用ADB命令操作Android的apk/aab包

keystore文件轉換jks文件 操作步驟&#xff1a; 步驟1&#xff0c;生成P12文件&#xff1a; keytool -importkeystore -srckeystore [文件名].keystore -srcstoretype JKS -deststoretype PKCS12 -destkeystore [文件名].p12 步驟2&#xff0c;生成jks文件&#xff1a; keytool…

圖文展示HDFS、YARN、MapReduce三者關系

MapReduce架構概述 MapReduce將計算過程分為兩個階段&#xff1a;Map和Reduce &#xff08;1&#xff09;Map階段并行處理輸入數據 &#xff08;2&#xff09;Reduce階段對Map結果進行匯總 HDFS、YARN、MapReduce三者關系

DL00219-基于深度學習的水稻病害檢測系統含源碼

&#x1f33e; 基于深度學習的水稻病害檢測系統 — 智能農業的未來&#xff0c;守護農田的每一寸土地&#xff01; &#x1f69c; 完整系統獲取見文末 水稻病害檢測&#xff0c;一直是農業領域的一大難題。傳統的人工檢測不僅耗時耗力&#xff0c;還容易因經驗不足導致漏檢或誤…

github 上的 CI/CD 的嘗試

效果 步驟 新建倉庫設置倉庫的 page 新建一個 vite 的項目&#xff0c;改一下 vite.config.js 中的 base 工作流 在項目的根目錄下新建一個 .github/workflows/ci.yml 文件&#xff0c;然后編輯一下內容 name: Build & Deploy Vue 3 Appon:push:branches: [main]permi…

鴻蒙5.0項目開發——鴻蒙天氣項目的實現(介紹)

【高心星出品】 文章目錄 項目簡介&#xff1a;項目運行效果圖&#xff1a;主要功能&#xff1a;使用的技能點&#xff1a;開發環境&#xff1a; 項目簡介&#xff1a; 這是一個基于鴻蒙系統&#xff08;HarmonyOS&#xff09;開發的天氣應用&#xff0c;采用 ArkTS 語言開發&…

SpringCloud之Eureka基礎認識-服務注冊中心

0、認識Eureka Eureka 是 Netflix 開源的服務發現組件&#xff0c;后來被集成到 Spring Cloud 生態中&#xff0c;成為 Spring Cloud Netflix 的核心模塊之一。它主要用于解決分布式系統中??服務注冊與發現??的問題。 Eureka Server 有必要的話&#xff0c;也可以做成集群…

【氮化鎵】電子輻照下溫度對GaN位移閾能的影響

2024年,華東師范大學的彭勝國等人基于從頭算分子動力學(AIMD)方法,研究了低能電子束輻照下溫度對氮化鎵(GaN)位移閾能(TDE)的影響。實驗結果表明,在初始動能40至80 eV的范圍內,鎵(Ga)和氮(N)原子作為初級擊出原子(PKAs)引發的位移對溫度呈現不同的敏感性:Ga 的…

Java 中的數據類型誤導點!!!

在 Java 中&#xff0c;數據類型分為兩大類&#xff1a;基本類型&#xff08;Primitive Types&#xff09; 和 引用類型&#xff08;Reference Types&#xff09;。它們的存儲方式和行為完全不同。 1. 基本類型 Java 有 8 種基本數據類型&#xff0c;它們直接存儲值&#xff…

二次封裝 el-dialog 組件:打造更靈活的對話框解決方案

文章目錄 引言為什么需要二次封裝&#xff1f;封裝思路代碼實現1. 基礎封裝組件 (Dialog.vue)2. Vue中引入使用示例 封裝后的優勢進階優化建議 總結 引言 在 Vue 項目中&#xff0c;Element UI 的 el-dialog 是一個非常實用的對話框組件。但在實際開發中&#xff0c;我們經常會…

框架篇八股(自用)

框架篇 Spring框架中的bean不是線程安全的 Scope&#xff08;&#xff09; singleton單例 prototype多例 一個類中有可修改的成員變量需要考慮線程安全 bean沒有可變狀態&#xff08;service類&#xff0c;DAO類&#xff09; 某種程度單例bean是線程安全的 AOP面向切面編程…

Go語言安裝proto并且使用gRPC服務(2025最新WINDOWS系統)

1.protobuf簡介 protobuf 即 Protocol Buffers&#xff0c;是一種輕便高效的結構化數據存儲格式&#xff0c;與語言、平臺無關&#xff0c;可擴展可序列化。protobuf 性能和效率大幅度優于 JSON、XML 等其他的結構化數據格式。protobuf 是以二進制方式存儲的&#xff0c;占用空…

rust-candle學習筆記11-實現一個簡單的自注意力

參考&#xff1a;about-pytorch 定義ScaledDotProductAttention結構體&#xff1a; use candle_core::{Result, Device, Tensor}; use candle_nn::{Linear, Module, linear_no_bias, VarMap, VarBuilder, ops};struct ScaledDotProductAttention {wq: Linear,wk: Linear,wv: …

spark MySQL數據庫配置

Spark 連接 MySQL 數據庫的配置 要讓 Spark 與 MySQL 數據庫實現連接&#xff0c;需要進行以下配置步驟。下面為你提供詳細的操作指南和示例代碼&#xff1a; 1. 添加 MySQL JDBC 驅動依賴 你得把 MySQL 的 JDBC 驅動添加到 Spark 的類路徑中。可以通過以下兩種方式來完成&a…

web 自動化之 KDT 關鍵字驅動詳解

一、什么是關鍵字驅動&#xff1f; 1、什么是關鍵字驅動&#xff1f;&#xff08;以關鍵字函數驅動測試&#xff09; 關鍵字驅動又叫動作字驅動&#xff0c;把項目業務封裝成關鍵字函數&#xff0c;再基于關鍵字函數實現自動化測試 2、關鍵字驅動測試原理 關鍵字驅動測試是一…

Java使用POI+反射靈活的控制字段導出Excel

前端傳入哪些字段&#xff0c;后端就導出哪些到Excel表格中&#xff0c;具體代碼實現如下 controller /*** 用戶導出* param dto*/PostMapping("/exportUser")public void exportCharterOrder(RequestBody UserExportDTO dto){userService.exportUser(dto);} serv…

Qt/C++面試【速通筆記八】—Qt的事件處理機制

在Qt中&#xff0c;事件處理機制是應用程序與用戶或系統交互的核心。通過事件處理&#xff0c;Qt能夠響應用戶的輸入、窗口的變化、定時器的觸發等各種情況。 1. 事件循環&#xff08;Event Loop&#xff09; 在Qt應用程序中&#xff0c;事件循環是事件處理機制的基礎。事件循…

TTL (Time-To-Live) 解析

文章目錄 TTL (Time-To-Live) 解析&#xff1a;網絡與Java中的應用一、TTL的定義二、TTL在網絡中的應用1. **路由和數據包的生命周期**2. **DNS中的TTL**3. **防止環路** 三、TTL在Java中的應用1. **緩存管理**2. **Java中的ThreadLocal**3. **網絡通信中的TTL** 四、TTL的注意…

HDFS的客戶端操作(2)文件上傳

我們向/maven下上傳一個文件。 要用到的api是put (或者copyFormLocalFile&#xff09;。核心代碼如下。 public void testCopyFromLocalFile() throws IOException, InterruptedException, URISyntaxException {// 1 獲取文件系統Configuration configuration new Configurati…

光譜相機的光電信號轉換

光譜相機的光電信號轉換是將分光后的光學信息轉化為可處理的數字信號的核心環節&#xff0c;具體分為以下關鍵步驟&#xff1a; 一、分光后光信號接收與光電轉換 ?分光元件作用? 光柵/棱鏡/濾光片等分光元件將入射光分解為不同波長單色光&#xff0c;投射至探測器陣列表面…

網絡協議分析 實驗二 IP分片與IPv6

文章目錄 索引及重要內容實驗2 IP 高級實驗實驗2.1 IPv4協議分片實驗實驗2.2 IPV6協議實驗2.3 ARP初級 索引及重要內容 實驗2 IP 高級實驗 實驗2.1 IPv4協議分片實驗 icmp的不可達報文 實驗2.2 IPV6協議 實驗2.3 ARP初級 arp –a 查看ARP緩存表內容 arp –s IP地址(格式&…