NetLink內核套接字案例分析

一、基礎知識

????????Netlink 是 Linux 系統中一種內核與用戶空間通信的高效機制,而?Netlink 消息是這種通信的核心載體。它允許用戶態程序(如網絡配置工具、監控工具)與內核子系統(如網絡協議棧、設備驅動)交換數據,例如獲取網絡接口信息、配置路由表、接收內核事件通知等。


Netlink 消息的組成

一個完整的 Netlink 消息由兩部分構成:

  1. 消息頭(struct nlmsghdr
    定義消息的元信息,例如消息類型、長度、序列號等。

    struct nlmsghdr {__u32 nlmsg_len;    // 消息總長度(頭部 + 數據)__u16 nlmsg_type;   // 消息類型(如請求、響應、錯誤)__u16 nlmsg_flags;  // 標志位(如請求標志、多部分消息標志)__u32 nlmsg_seq;    // 序列號(用于匹配請求和響應)__u32 nlmsg_pid;    // 發送方端口ID(通常為進程ID)
    };
  2. 消息體(Payload)
    具體的數據內容,格式由消息類型決定。例如:

    • 路由消息:struct rtgenmsg(指定地址族)

    • 接口信息:struct ifinfomsg(接口索引、狀態等)

    • 屬性列表:動態附加的屬性(如接口名稱、MAC地址等)。


Netlink 消息的作用

Netlink 消息的核心功能是雙向通信

1. 用戶空間 → 內核

用戶程序通過發送 Netlink 消息向內核發起操作請求。例如:

  • 查詢信息RTM_GETLINK(獲取網絡接口列表)、RTM_GETROUTE(獲取路由表)。

  • 配置內核RTM_NEWLINK(創建新接口)、RTM_SETLINK(修改接口屬性)。

2. 內核 → 用戶空間

內核通過 Netlink 消息主動通知用戶程序事件。例如:

  • 接口狀態變化:網絡接口啟用/禁用。

  • 新設備插入:USB 設備連接、Wi-Fi 網絡掃描結果。

  • 路由表更新:路由條目添加或刪除。


為什么用 Netlink?

與其他內核通信方式相比,Netlink 的優勢在于:

機制特點適用場景
Netlink雙向、異步、支持多播、結構化數據、可擴展動態配置和實時事件通知
Sysfs通過文件系統操作(/sys),讀寫簡單但效率低靜態配置(如設置參數)
Procfs通過文件系統(/proc),主要用于狀態查詢讀取系統信息(如進程狀態)
ioctl通過設備文件操作,接口不統一,擴展性差設備驅動特定操作
Netlink 的獨特優勢
  1. 結構化數據
    消息通過二進制格式傳遞,避免了文本解析(如?procfs/sysfs)的開銷。

  2. 異步通信
    支持非阻塞通信,用戶程序無需等待內核響應。

  3. 多播支持
    內核可以向多個用戶進程廣播事件(如接口狀態變化)。

  4. 可擴展性
    通過消息類型(nlmsg_type)和屬性(struct rtattr)靈活擴展功能。


Netlink 消息的工作流程

以獲取網絡接口列表為例:

  1. 用戶程序構造請求消息

    • 設置?nlmsghdrnlmsg_type = RTM_GETLINKnlmsg_flags = NLM_F_DUMP

    • 設置?rtgenmsgrtgen_family = AF_UNSPEC(獲取所有接口)。

  2. 發送消息到內核
    通過?sendmsg?系統調用發送 Netlink 消息。

  3. 內核處理請求
    路由子系統解析消息,收集所有網絡接口信息,封裝為多個 Netlink 消息(可能分片)。

  4. 用戶程序接收響應
    通過?recvmsg?讀取消息,解析?nlmsghdr?和消息體,提取接口名稱、狀態等數據。


典型應用場景

  1. 網絡配置工具
    iproute2?工具集(如?ip linkip route)底層使用 Netlink 配置網絡。

  1. 設備監控
    監聽內核事件,如接口狀態變化、新設備連接。

  2. 防火墻和策略路由
    配置?netfilter(iptables/nftables)規則或復雜路由策略。

  3. 容器網絡
    容器運行時(如 Docker)通過 Netlink 管理虛擬網絡設備。

?

1.nlinterfaces.c

// 程序功能:應用Netlink套接字從Linux內核打印輸出所有網絡接口名稱
#include <bits/types/struct_iovec.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>  //Netlink協議相關定義
#include <linux/rtnetlink.h> // 路由相關的Netlink消息定義#define BUFSIZE 10240//定義一個自定義結構體ln_request_s,它包含一個 Netlink 消息頭nlmsghdr和一個路由通用消息結構體rtgenmsg
struct In_request_s{//Netlink消息頭struct nlmsghdr hdr;//路由消息通用結構,指定地址族struct rtgenmsg gen;
};//功能:解析并打印網絡接口信息
void rtnl_print_link(struct nlmsghdr *h){//struct ifinfomsg *iface:指向 Netlink 消息中包含的網絡接口信息結構體struct ifinfomsg *iface;//struct rtattr *attr:指向路由屬性結構體struct  rtattr *attr;int len = 0;//獲取 Netlink 消息中實際的數據部分,計算方式:消息頭地址 + 頭部大小iface = NLMSG_DATA(h);//獲取 Netlink 消息中有效負載的長度len = RTM_PAYLOAD(h);//遍歷路由屬性for(attr = IFLA_RTA(iface);RTA_OK(attr,len);attr = RTA_NEXT(attr,len)){switch (attr->rta_type){//如果屬性是接口名稱就打印case IFLA_IFNAME:printf("接口名稱%d : %s\n", iface->ifi_index, (char *)RTA_DATA(attr));break;default:break;}}
}int main(int argc,char *argv[]){//Netlink地址結構,用于綁定套接字struct sockaddr_nl nkernel;//消息頭結構,用于 sendmsg 和 recvmsgstruct msghdr msg;//分散、聚集I/O結構,用于消息傳輸,主要跟readv、writev等緩沖區合并有關,用于一次I/O操作處理多個緩沖區struct iovec io;//自定義請求結構struct In_request_s req;//s為套接字描述符,end為循環結束標志int s = -1, end = 0, ret;//接收緩沖區char buf[BUFSIZE];//初始化Netlink地址結構memset(&nkernel,0,sizeof(nkernel));nkernel.nl_family = AF_NETLINK;    //這里與內核通信所以不使用AF_INETnkernel.nl_groups = 0; // 不加入任何組播組//創建套接字/*AF_NETLINK: 使用 Netlink 協議族。SOCK_RAW: 原始套接字類型,允許直接操作 Netlink 消息。NETLINK_ROUTE: 路由子系統,用于獲取網絡接口和路由信息。*/if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0){printf("創建Netlink套接字失敗.\n");exit(EXIT_FAILURE);}//構造Netlink請求消息memset(&req, 0, sizeof(req));//#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))//nlmsg_len: 消息總長度(頭部 + rtgenmsg 結構體),通過 NLMSG_LENGTH 計算對齊后的長度req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));//請求獲取網絡接口信息req.hdr.nlmsg_type = RTM_GETLINK;//標志為請求消息,并要求返回所有條目req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;//序列號,用于匹配請求和響應req.hdr.nlmsg_seq = 1;//發送方進程 IDreq.hdr.nlmsg_pid = getpid();//指定地址族為 IPv4(可改為 AF_UNSPEC 獲取所有接口)req.gen.rtgen_family = AF_INET;//設置I/O向量和消息頭memset(&io, 0, sizeof(io));io.iov_base = &req;io.iov_len = req.hdr.nlmsg_len;memset(&msg, 0, sizeof(msg));msg.msg_iov = &io;          // 指向 I/O 向量msg.msg_iovlen = 1;         // 向量數量為 1msg.msg_name = &nkernel;    // 目標地址(內核)msg.msg_namelen = sizeof(nkernel);//發送請求消息if ((ret = sendmsg(s, &msg, 0)) < 0) {perror("發送消息失敗");close(s);exit(EXIT_FAILURE);}//接收并解析內核響應,,當接收到 NLMSG_DONE 消息時,end 會被置為 1,從而退出循環while(!end){//定義一個指向 nlmsghdr 結構體的指針 msg_ptr,用于遍歷接收到的 Netlink 消息struct nlmsghdr *msg_ptr;//用于記錄還未處理的消息長度int remaining_len;memset(buf, 0, BUFSIZE);io.iov_base = buf;io.iov_len = BUFSIZE;if ((ret = recvmsg(s, &msg, 0)) < 0) {if (errno == EINTR) continue;  // 處理中斷perror("接收消息失敗");close(s);exit(EXIT_FAILURE);}// 處理消息分片(NLMSG_TRUNC標志)if (msg.msg_flags & MSG_TRUNC) {fprintf(stderr, "警告:消息被截斷,考慮增大緩沖區\n");}//將 msg_ptr 指針指向接收緩沖區 buf 的起始位置,將其視為第一個 Netlink 消息的頭部msg_ptr = (struct nlmsghdr *)buf;//將 remaining_len 初始化為接收到的消息總長度 retremaining_len = ret;for (; NLMSG_OK(msg_ptr, remaining_len);   //NLMSG_OK(msg_ptr, remaining_len):這是一個宏,用于檢查 msg_ptr 指向的 Netlink 消息是否有效,即消息長度是否足夠且未超出剩余未處理的消息長度msg_ptr = NLMSG_NEXT(msg_ptr, remaining_len)) {  //將 msg_ptr 指針移動到下一個 Netlink 消息的頭部,并更新 remaining_len 的值//內核在回復單播請求時,會將 nlmsg_pid 設置為用戶進程的 PID(即 self_pid)if (msg_ptr->nlmsg_pid != getpid()) {fprintf(stderr, "收到非本進程的消息,已忽略 (PID: %u)\n", msg_ptr->nlmsg_pid);continue;}   switch (msg_ptr->nlmsg_type) {case NLMSG_ERROR: {  //如果消息類型為 NLMSG_ERROR,表示內核返回了錯誤信息struct nlmsgerr *err = NLMSG_DATA(msg_ptr);  //使用 NLMSG_DATA 宏獲取消息中的錯誤信息結構體 nlmsgerr 的指針if (err->error != 0) {fprintf(stderr, "內核返回錯誤: %s\n", strerror(-err->error));close(s);exit(EXIT_FAILURE);}break;}case NLMSG_DONE: //如果消息類型為 NLMSG_DONE,表示內核已經發送完所有請求的信息,將 end 標志置為 1,退出循環end = 1;break;case RTM_NEWLINK: //如果消息類型為 RTM_NEWLINK,表示接收到了新的網絡接口信息。調用 rtnl_print_link 函數處理該消息,打印網絡接口的相關信息rtnl_print_link(msg_ptr);break;default:   //如果消息類型不是上述幾種情況,輸出忽略消息的信息,包含消息類型和消息長度printf("忽略消息:type=%d, len=%d\n",msg_ptr->nlmsg_type, msg_ptr->nlmsg_len);break;}}// 處理未對齊的剩余數據if (remaining_len > 0) {fprintf(stderr, "剩余%d字節未處理數據\n", remaining_len);}}close(s);  // 確保關閉套接字return 0;
}

編譯運行:

二、ipaddress.c

// 顯示IPv4,應用Netlink套接字從Linux內核中獲取所有網絡接口的IP地址
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <errno.h>#define BUFFERSIZE 10240// 定義一個自定義結構體 netlink_reqest_s,它包含一個 Netlink 消息頭 nlmsghdr 和一個路由通用消息結構體 rtgenmsg
struct netlink_reqest_s {// Netlink 消息頭struct nlmsghdr hdr;// 路由消息通用結構,指定地址族struct rtgenmsg gen;
};// 功能:解析并打印網絡接口的 IP 地址信息
void rtnetlink_disp_address(struct nlmsghdr *h) {// struct ifaddrmsg *addr:指向 Netlink 消息中包含的網絡地址信息結構體struct ifaddrmsg *addr;// struct rtattr *attr:指向路由屬性結構體struct rtattr *attr;// 用于記錄 Netlink 消息中有效負載的長度int len;// 獲取 Netlink 消息中實際的數據部分,計算方式:消息頭地址 + 頭部大小addr = NLMSG_DATA(h);// 獲取 Netlink 消息中有效負載的長度len = RTM_PAYLOAD(h);/* 循環輸出 Netlink 所有屬性消息:網絡接口名稱及 IP 地址 */for (attr = IFA_RTA(addr); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {switch (attr->rta_type) {// 如果屬性是接口名稱就打印case IFA_LABEL:printf("網絡接口名稱 : %s\n", (char *)RTA_DATA(attr));break;// 如果屬性是本地 IP 地址就打印case IFA_LOCAL: {// 獲取 IP 地址的二進制表示int ip = *(int *)RTA_DATA(attr);// 用于存儲 IP 地址的四個字節unsigned char bytes[4];// 提取 IP 地址的四個字節bytes[0] = ip & 0xFF;bytes[1] = (ip >> 8) & 0xFF;bytes[2] = (ip >> 16) & 0xFF;bytes[3] = (ip >> 24) & 0xFF;// 打印網絡 IP 地址printf("網絡 IP 地址為 : %d.%d.%d.%d\n\n", bytes[0], bytes[1], bytes[2], bytes[3]);break;}default:break;}}
}int main(void) {// Netlink 地址結構,用于綁定套接字struct sockaddr_nl kerl;// 套接字描述符int s;// 循環結束標志int end = 0;// 接收到的消息長度int len;// 消息頭結構,用于 sendmsg 和 recvmsgstruct msghdr msg;// 自定義請求結構struct netlink_reqest_s req;// 分散、聚集 I/O 結構,用于消息傳輸struct iovec io;// 接收緩沖區char buffer[BUFFERSIZE];// 初始化 Netlink 地址結構memset(&kerl, 0, sizeof(kerl));// 使用 Netlink 協議族kerl.nl_family = AF_NETLINK;// 不加入任何組播組kerl.nl_groups = 0;// 創建套接字/*AF_NETLINK: 使用 Netlink 協議族。SOCK_RAW: 原始套接字類型,允許直接操作 Netlink 消息。NETLINK_ROUTE: 路由子系統,用于獲取網絡接口和路由信息。*/if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {perror("創建 Netlink 套接字失敗");exit(EXIT_FAILURE);}// 構造 Netlink 請求消息memset(&req, 0, sizeof(req));// 消息總長度(頭部 + rtgenmsg 結構體),通過 NLMSG_LENGTH 計算對齊后的長度req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));// 請求獲取網絡接口地址信息req.hdr.nlmsg_type = RTM_GETADDR;// 標志為請求消息,并要求返回所有條目req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;// 序列號,用于匹配請求和響應req.hdr.nlmsg_seq = 1;// 發送方進程 IDreq.hdr.nlmsg_pid = getpid();// 指定地址族為 IPv4req.gen.rtgen_family = AF_INET;// 設置 I/O 向量和消息頭memset(&io, 0, sizeof(io));io.iov_base = &req;io.iov_len = req.hdr.nlmsg_len;memset(&msg, 0, sizeof(msg));msg.msg_iov = &io;          // 指向 I/O 向量msg.msg_iovlen = 1;         // 向量數量為 1msg.msg_name = &kerl;       // 目標地址(內核)msg.msg_namelen = sizeof(kerl);// 發送請求消息if (sendmsg(s, &msg, 0) < 0) {perror("發送消息失敗");close(s);exit(EXIT_FAILURE);}// 接收并解析內核響應,當接收到 NLMSG_DONE 消息時,end 會被置為 1,從而退出循環while (!end) {// 定義一個指向 nlmsghdr 結構體的指針 msg_ptr,用于遍歷接收到的 Netlink 消息struct nlmsghdr *msg_ptr;// 用于記錄還未處理的消息長度int remaining_len;// 清空接收緩沖區memset(buffer, 0, BUFFERSIZE);io.iov_base = buffer;io.iov_len = BUFFERSIZE;// 接收消息if ((len = recvmsg(s, &msg, 0)) < 0) {if (errno == EINTR) continue;  // 處理中斷perror("接收消息失敗");close(s);exit(EXIT_FAILURE);}// 處理消息分片(NLMSG_TRUNC 標志)if (msg.msg_flags & MSG_TRUNC) {fprintf(stderr, "警告:消息被截斷,考慮增大緩沖區\n");}// 將 msg_ptr 指針指向接收緩沖區 buffer 的起始位置,將其視為第一個 Netlink 消息的頭部msg_ptr = (struct nlmsghdr *)buffer;// 將 remaining_len 初始化為接收到的消息總長度 lenremaining_len = len;for (; NLMSG_OK(msg_ptr, remaining_len);  // NLMSG_OK(msg_ptr, remaining_len):這是一個宏,用于檢查 msg_ptr 指向的 Netlink 消息是否有效,即消息長度是否足夠且未超出剩余未處理的消息長度msg_ptr = NLMSG_NEXT(msg_ptr, remaining_len)) {  // 將 msg_ptr 指針移動到下一個 Netlink 消息的頭部,并更新 remaining_len 的值// 內核在回復單播請求時,會將 nlmsg_pid 設置為用戶進程的 PID(即 self_pid)if (msg_ptr->nlmsg_pid != getpid()) {fprintf(stderr, "收到非本進程的消息,已忽略 (PID: %u)\n", msg_ptr->nlmsg_pid);continue;}switch (msg_ptr->nlmsg_type) {// 如果消息類型為 NLMSG_ERROR,表示內核返回了錯誤信息case NLMSG_ERROR: {// 使用 NLMSG_DATA 宏獲取消息中的錯誤信息結構體 nlmsgerr 的指針struct nlmsgerr *err = NLMSG_DATA(msg_ptr);if (err->error != 0) {fprintf(stderr, "內核返回錯誤: %s\n", strerror(-err->error));close(s);exit(EXIT_FAILURE);}break;}// 如果消息類型為 NLMSG_DONE,表示內核已經發送完所有請求的信息,將 end 標志置為 1,退出循環case NLMSG_DONE:end = 1;break;// 如果消息類型為 RTM_NEWADDR,表示接收到了新的網絡接口地址信息。調用 rtnetlink_disp_address 函數處理該消息,打印網絡接口的相關信息case RTM_NEWADDR:rtnetlink_disp_address(msg_ptr);break;// 如果消息類型不是上述幾種情況,輸出忽略消息的信息,包含消息類型和消息長度default:printf("忽略消息:type=%d, len=%d\n", msg_ptr->nlmsg_type, msg_ptr->nlmsg_len);break;}}// 處理未對齊的剩余數據if (remaining_len > 0) {fprintf(stderr, "剩余 %d 字節未處理數據\n", remaining_len);}}// 確保關閉套接字close(s);return 0;
}    

編譯運行:

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

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

相關文章

批量壓縮與優化 Excel 文檔,減少 Excel 文檔大小

當我們在 Excel 文檔中插入圖片資源的時候&#xff0c;如果我們插入的是原圖&#xff0c;可能會導致 Excel 變得非常的大。這非常不利于我們傳輸或者共享。那么當我們的 Excel 文件非常大的時候&#xff0c;我們就需要對文檔做一些壓縮或者優化的處理。那有沒有什么方法可以實現…

基于深度學習的多模態人臉情緒識別研究與實現(視頻+圖像+語音)

這是一個結合圖像和音頻的情緒識別系統&#xff0c;從架構、數據準備、模型實現、訓練等。包括數據收集、預處理、模型訓練、融合方法、部署優化等全流程。確定完整系統的組成部分&#xff1a;數據收集與處理、模型設計與訓練、多模態融合、系統集成、部署優化、用戶界面等。詳…

保姆級離線TiDB V8+解釋

以前學習的時候還是3版本&#xff0c;如今已經是8版本了 https://cn.pingcap.com/product-community/?_gl1ujh2l9_gcl_auMTI3MTI3NTM3NC4xNzM5MjU3ODE2_gaMTYwNzE2NTI4OC4xNzMzOTA1MjUz_ga_3JVXJ41175MTc0MTk1NTc1OC4xMS4xLjE3NDE5NTU3NjIuNTYuMC41NDk4MTMxNTM._ga_CPG2VW1Y4…

spark實驗2

一.實驗題目 實驗所需要求&#xff1a; centos7虛擬機 pyspark spark python3 hadoop分布式 統計歷屆春晚的節目數目 統計各個類型節目的數量&#xff0c;顯示前10名 統計相聲類節目歷年的數目。 查詢每個演員在春晚上表演節目的數量。 統計每年各類節目的數量&#xff0…

學習文章:Spring Boot 中如何使用 `@Async` 實現異步處理

文章目錄 學習文章&#xff1a;Spring Boot 中如何使用 Async 實現異步處理 一、什么是 Async&#xff1f;優點&#xff1a; 二、Spring Boot 中啟用 Async1. 啟用異步支持2. 配置線程池&#xff08;可選&#xff09;3. 使用 Async 注解4. 調用異步方法 三、Async 的進階用法1.…

Manus:成為AI Agent領域的標桿

一、引言 官網&#xff1a;Manus 隨著人工智能技術的飛速發展&#xff0c;AI Agent&#xff08;智能體&#xff09;作為人工智能領域的重要分支&#xff0c;正逐漸從概念走向現實&#xff0c;并在各行各業展現出巨大的應用潛力。在眾多AI Agent產品中&#xff0c;Manus以其獨…

Git Fast-forward 合并詳解:原理、場景與最佳實踐

在使用 Git 進行團隊協作時&#xff0c;我們經常需要合并分支。合并方式有很多種&#xff0c;其中 Fast-forward&#xff08;快速合并&#xff09; 是一種最簡單且無沖突的合并方式。本文將詳細介紹 Fast-forward 的原理、適用場景、常見問題及最佳實踐。 一、Fast-forward 合并…

命令行重啟Ubuntu軟件

我是用Todesk遠程桌面&#xff0c;如果卡死的時候&#xff0c;只能通過ssh連接命令行。于是&#xff0c;就有了如標題所示的需求。 首先&#xff0c;我們看一下todesk在系統里叫什么名字&#xff1a; systemctl list-unit-files | grep -i todesk看到發現是"todeskd.serv…

算法每日一練 (11)

&#x1f4a2;歡迎來到張胤塵的技術站 &#x1f4a5;技術如江河&#xff0c;匯聚眾志成。代碼似星辰&#xff0c;照亮行征程。開源精神長&#xff0c;傳承永不忘。攜手共前行&#xff0c;未來更輝煌&#x1f4a5; 文章目錄 算法每日一練 (11)全排列題目描述解題思路解題代碼c/c…

《Spring日志整合與注入技術:從入門到精通》

1.Spring與日志框架的整合 1.Spring與日志框架進行整合&#xff0c;日志框架就可以在控制臺中&#xff0c;輸出Spring框架運行過程中的一些重要的信息。 好處&#xff1a;方便了解Spring框架的運行過程&#xff0c;利于程序的調試。 Spring如何整合日志框架 Spring5.x整合log4j…

《SQL性能優化指南:新手如何寫出高效的數據庫查詢

新手程序員如何用三個月成為SQL高手&#xff1f;萬字自學指南帶你彎道超車 在數據為王的時代&#xff0c;掌握SQL已成為職場新人的必修課。你可能不知道&#xff0c;僅用三個月系統學習&#xff0c;一個零基礎的小白就能完成從數據庫萌新到SQL達人的蛻變。去年剛畢業的小王就是…

【Unity】在項目中使用VisualScripting

1. 在packagemanager添加插件 2. 在設置中進行初始化。 Edit > Project Settings > Visual Scripting Initialize Visual Scripting You must select Initialize Visual Scripting the first time you use Visual Scripting in a project. Initialize Visual Scripting …

JConsole 在 Linux 上的使用

JConsole 在 Linux 上的使用指南 1. 啟動 JConsole 遠程監控 Linux 服務器上的 JVM 進程 1.1 修改 JMX 配置&#xff0c;允許遠程訪問 在 Linux 服務器 啟動 Java 應用時&#xff0c;需要加上 -Djava.rmi.server.hostname<服務器IP>&#xff0c;完整的啟動參數如下&am…

個人記錄,Unity資源解壓和管理插件

就是經典的兩個AssetStudio 和 Ripper 沒有什么干貨&#xff0c;就是記錄一下&#xff0c;內容沒有很詳細 AssetStudio 說錯了&#xff0c;AssetStudio比較出名&#xff08;曾經&#xff09;&#xff0c;但好像墮落了 是&#xff0c;AssetBundlExtractor 這個工具有個好處就…

編譯skia

1.準備工具 (1)vs2019,到微軟官方下載下載 Visual Studio Tools - 免費安裝 Windows、Mac、Linux (2)ninja,下載地址:Releases ninja-build/ninja GitHub (3)gn,下載地址:https://chrome-infra-packages.appspot.com/p/gn/gn/windows-amd64 (4)skia,下載地址:git …

vue 知識點整理

1.data為什么是一個函數而不是對象 維度對象形式函數形式數據隔離性所有實例共享同一對象&#xff0c;導致數據污染每個實例擁有獨立數據副本復用安全性不適用于可復用組件支持組件安全復用語言機制引用傳遞引發副作用函數返回值實現作用域隔離&#xff08;閉包&#xff09;框…

DeepSeek-Open WebUI部署

1.DeepSeek部署-Win版本 2.DeepSeek部署-Linux版本 3.DeepSeek部署-一鍵部署(Linux版本) 4.DeepSeek部署-進階版本(LinuxGPU) 5.DeepSeek部署-基于vLLM部署 前面部署了vLLM版本以后&#xff0c;訪問它比較麻煩。如何才能更好的實現訪問呢&#xff0c;這個就是我們今天要講的…

(vue)elementUi中el-upload上傳附件之后 點擊附件可下載

(vue)elementUi中el-upload上傳附件之后 點擊附件可下載 handlePreview(file) {console.log(file)const fileUrl https://.../zzy/ file.urlconst a document.createElement(a)a.href fileUrla.download file.namea.style.display none// a.setAttribute(download, file.…

你認為 Java 的優勢是什么?

你認為 Java 的優勢是什么? 回答重點 我覺得可以從跨平臺、垃圾回收、生態、面向對象四個方面來闡述。 跨平臺 首先 Java 是跨平臺的,不同平臺執行的機器碼是不一樣的,而 Java 因為加了一層中間層 JVM,所以可以做到一次編寫多平臺(如 Windows、Linux、macOS)運行,即…

SpringBoot——Maven篇

Spring Boot 是一個用于快速開發基于 Spring 框架的應用程序的工具。它具有許多特性&#xff0c;其中一些重要的特性包括&#xff1a; 1. 自動配置&#xff1a;Spring Boot 提供了自動配置的機制&#xff0c;可以根據應用程序的依賴和環境自動配置應用程序的各種組件&#xff…