netlink---Linux下基于socket的内核和上层通信机制

通过NETLINK_KOBJECT_UEVENT捕获udev的uevent 测试代码如下: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <sys/un.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <linux/types.h> #include <linux/netlink.. 阅读详情
需要在linux网卡驱动中加入一个自己的驱动,实现在内核态完成一些报文处理(这个过程可以实现一种零COPY的网络报文截获),对于复杂报文COPY下必要的数据交给用户态来完成(因为过于复杂的报文消耗CPU太大,会导致中断占用时间太长)。因此需要一种内核和用户态配合的通信机制,尝试了很多方式都不太理想,最后采用netlink+内存映射的模式很好的解决了这个问题。Netlink是一种采用socket通信的机制,用于linux内核和上层用户空间进行通信的一种机制,通过实践我认为netlink最大的优点是可以实现“双向通信”,是内核向用户态发起通知的一种最好选择。


内核和用户空间进行通信,大概有如下几种方式可以考虑:
采用内存映射的方式,将内核地址映射到用户态。这种方式最直接,可以适用大量的数据传输机制。这种方式的缺点是很难进行“业务控制”,没有一种可靠的机制保障内核和用户态的调动同步,比如信号量等都不能跨内核、用户层使用。因此内存映射机制一般需要配合一种“消息机制”来控制数据的读取,比如采用“消息”类型的短数据通道来完成一个可靠的数据读取功能。
ioctl机制,ioctl机制可以在驱动中扩展特定的ioctl消息,用于将一些状态从内核反应到用户态。Ioctl有很好的数据同步保护机制,不要担心内核和用户层的数据访问冲突,但是ioctl不适合传输大量的数据,通过和内存映射结合可以很好的完成大量数据交换过程。但是,ioctl的发起方一定是在用户态,因此如果需要内核态主动发起一个通知消息给用户层,则非常的麻烦。可能需要用户态程序采用轮询机制不停的ioctl。
其他一些方式比如系统调用必须通过用户态发起,proc方式不太可靠和实时,用于调试信息的输出还是非常合适的。
通过前面的项目背景,我需要一种可以在内核态主动发起消息的通知方式,而用户态的程序最好可以采用一种“阻塞调用”的方式等待消息。这样的模型可以最大限度的节省CPU的调度,同时可以满足及时处理的要求,最终选择了netlink完成通信的过程。
Netlink的通信模型和socket通信非常相似,主要要点如下:
  • netlink采用自己独立的地址编码,struct sockaddr_nl;
  • 每个通过netlink发出的消息都必须附带一个netlink自己的消息头,struct nlmsghdr;
  • 内核态的netlink的操作API和用户态完全不一样,后面再介绍;
  • 用户态的netlink操作完成采用socket函数,非常方便和简单,有TCP/UDP socket编程基础的非常容易上手。


Netlink的通信地址和协议

所有socket之间的通信,必须有个地址结构,Netlink也不例外。我们最熟悉的就是IPV4的地址了,netlink的地址结构如下:
  1. struct sockaddr_nl  
  2. {  
  3.     sa_family_t nl_family;          //必须为AF_NETLINK或者PF_NETLINK  
  4.     unsigned short  nl_pad;             //必须为0  
  5.     __u32       nl_pid;             //通信端口  
  6. __u32       nl_groups;              //组播掩码  
  7. };  

上面几个数据,最关键的是nl_family(就对应IP通信中的AF_INET)和nl_pid。

nl_pid就是一个约定的通信端口,用户态使用的时候需要用一个非0的数字,一般来说可以直接采用上层应用的进程ID(不用进程ID号码也没事,只要系统中不冲突的一个数字即可使用)。对于内核的地址,该值必须用0,也就是说,如果上层通过sendto向内核发送netlink消息,peer addr中nl_pid必须填写0。


nl_groups用于一个消息同时分发给不同的接收者,是一种组播应用,本文不讲组播应用。


本质上,nl_pid就是netlink的通信地址。除了通信地址,netlink还提供“协议”来标示通信实体,在创建socket的时候,需要指定netlink的通信协议号。每个协议号代表一种“应用”,上层可以用内核已经定义的协议和内核进行通信,获得内核已经提供的信息。具体支持的协议列表如下:

  1. #define NETLINK_ROUTE       0   /* Routing/device hook              */  
  2. #define NETLINK_UNUSED      1   /* Unused number                */  
  3. #define NETLINK_USERSOCK    2   /* Reserved for user mode socket protocols  */  
  4. #define NETLINK_FIREWALL    3   /* Firewalling hook             */  
  5. #define NETLINK_INET_DIAG   4   /* INET socket monitoring           */  
  6. #define NETLINK_NFLOG       5   /* netfilter/iptables ULOG */  
  7. #define NETLINK_XFRM        6   /* ipsec */  
  8. #define NETLINK_SELINUX     7   /* SELinux event notifications */  
  9. #define NETLINK_ISCSI       8   /* Open-iSCSI */  
  10. #define NETLINK_AUDIT       9   /* auditing */  
  11. #define NETLINK_FIB_LOOKUP  10    
  12. #define NETLINK_CONNECTOR   11  
  13. #define NETLINK_NETFILTER   12  /* netfilter subsystem */  
  14. #define NETLINK_IP6_FW      13  
  15. #define NETLINK_DNRTMSG     14  /* DECnet routing messages */  
  16. #define NETLINK_KOBJECT_UEVENT  15  /* Kernel messages to userspace */  
  17. #define NETLINK_GENERIC     16  
  18. /* leave room for NETLINK_DM (DM Events) */  
  19. #define NETLINK_SCSITRANSPORT   18  /* SCSI Transports */  
  20. #define NETLINK_ECRYPTFS    19  

协议的用途很好理解,比如我们单纯创建一个上层应用,通过和NETLINK_ROUTE协议通信,可以获得内核的路由信息。我需要利用netlink创建一个我自己的通信协议,因此我定义了一种新的协议。新协议的定义不能和内核已经定义的冲突,同时不能超过MAX_LINKS这个宏的限定,MAX_LINKS = 32。所以我定义的协议号为30。


小结:netlink采用协议号+通信端口的方式构建自己的地址体系。


用户态操作netlink socket

用户态创建netlink socket的基本过程和操作其他socket的API一模一样,区别就2点:
1、 netlink有自己的地址;
2、 netlink接收到的消息带一个netlink自己的消息头;


用户态创建、销毁socket的过程:
1、 用socket函数创建,socket(PF_NETLINK, SOCK_DGRAM, NETLINK_XXX);第一个参数必须是PF_NETLINK或者AF_NETLINK,第二个参数用SOCK_DGRAM和SOCK_RAW都没问题,第三个参数就是netlink的协议号。
2、 用bind函数绑定自己的地址。
3、 用close关闭套接字。

创建socket的代码样例:

  1. {  
  2.     struct sockaddr_nl addr;  
  3.     int flags;  
  4.      
  5.     //建立netlink socket  
  6.     s_nlm_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_XXX);  
  7.     if(s_nlm_socket < 0)  
  8.     {  
  9.         USE_DBG_OUT("create netlink socket error.\r\n");  
  10.         goto Err_Exit;  
  11.     }  
  12.       
  13.     //bind  
  14.     addr.nl_family = PF_NETLINK;  
  15.     addr.nl_pad    = 0;  
  16.     addr.nl_pid    = getpid();  
  17.     addr.nl_groups = 0;  
  18.       
  19.     if(bind(s_nlm_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0)  
  20.     {  
  21.         USE_DBG_OUT("bind socket error.\r\n");  
  22.         goto Err_Exit;  
  23.     }  
  24.   
  25.   
  26.     //设置socket为非阻塞模式  
  27.     flags = fcntl(s_nlm_socket, F_GETFL, 0);  
  28.     fcntl(s_nlm_socket, F_SETFL, flags|O_NONBLOCK);  
  29.       
  30.   
  31.   
  32.     return 0;  
  33. Err_Exit:  
  34.     return -1;  
  35. }  


用户态接收、发送消息的API:
用户态用sendto向内核发送netlink消息,用recvfrom接收消息。只是注意,发送、接收的时候在自己附带的消息前面要加上一个netlink的消息头。例如,定义一个如下的消息通信结构:

  1. struct tag_rcv_buf  
  2. {  
  3.         struct nlmsghdr hdr;            //netlink的消息头  
  4.         netlink_notify_s my_msg;        //通信实体消息  
  5. }st_snd_buf;  

发送代码的例子:

  1. My_send_msg  
  2. {  
  3.     struct tag_rcv_buf  
  4.     {  
  5.         struct nlmsghdr hdr;            //netlink的消息头  
  6.         netlink_notify_s my_msg;        //通信实体消息  
  7.     }st_snd_buf;  
  8.     fd_set st_write_set;                         //select fd,避免线程吊死  
  9.     struct timeval write_time_out = {10, 0};     //10秒超时  
  10.     int ret;  
  11.       
  12.     //设置select  
  13.     FD_ZERO(&st_write_set);  
  14.     FD_SET(s_nlm_socket, &st_write_set);  
  15.       
  16.     /* 
  17.         设置发送数据 
  18.     */  
  19.     st_snd_buf.hdr.nlmsg_len   = sizeof(st_snd_buf);        //NLMSG_LENGTH(sizeof(netlink_notify_s))--这个宏包含有头  
  20.     st_snd_buf.hdr.nlmsg_flags = 0;                         /*消息的附加选项,没啥用*/  
  21.     st_snd_buf.hdr.nlmsg_type  = 0;                         /*设置自定义消息类型*/  
  22.     st_snd_buf.hdr.nlmsg_pid   = getpid();                  /*设置发送者的PID*/  
  23.   
  24.   
  25.     st_snd_buf.my_msg.start_pack_id = s_id;  
  26.     st_snd_buf.my_msg.end_pack_id   = e_id;  
  27.       
  28.     ret = select(s_nlm_socket+1, NULL, &st_write_set, NULL, &write_time_out);  
  29.     if(ret == -1)  
  30.     {  
  31.         //have some error.  
  32.         USE_DBG_OUT("send has some error %d.\n", errno);  
  33.         goto out;  
  34.     }  
  35.     else if(ret == 0)  
  36.     {  
  37.         //超时退出  
  38.         TMP_DBG_OUT("send timeout.\n");  
  39.         goto out;  
  40.     }  
  41.     else  
  42.     {  
  43.         //接收消息  
  44.         ret = sendto(s_nlm_socket, &st_snd_buf, sizeof(st_snd_buf), 0,   
  45.                         (struct sockaddr*)&s_peer_addr, sizeof(s_peer_addr));  
  46.   
  47.   
  48.         if(ret < 0)  
  49.         {  
  50.             USE_DBG_OUT("send to kernal by nl error %d\r\n", errno);  
  51.         }  
  52.         else  
  53.         {  
  54.             TMP_DBG_OUT("send to kernal ok s_id is %d, e_id is %d.\r\n", s_id, e_id);  
  55.         }  
  56.     }  
  57.       
  58. out:      
  59.     return;  
  60. }  

接收数据的代码例子:

  1. {  
  2.     struct tag_rcv_buf  
  3.     {  
  4.         struct nlmsghdr hdr;            //netlink的消息头  
  5.         netlink_notify_s my_msg;        //通信实体消息  
  6.     }st_rcv_buf;  
  7.     int ret, addr_len, io_ret;  
  8.     struct sockaddr_nl st_peer_addr;  
  9.     fd_set st_read_set;                         //select fd,避免线程吊死  
  10.     struct timeval read_time_out = {10, 0};     //10秒超时  
  11.     int rcv_buf;  
  12.       
  13.     //设置内核的通信地址  
  14.     st_peer_addr.nl_family = AF_NETLINK;  
  15.     st_peer_addr.nl_pad = 0;                                   /*always set to zero*/  
  16.     st_peer_addr.nl_pid = 0;                                   /*kernel's pid is zero*/  
  17.     st_peer_addr.nl_groups = 0;                                /*multicast groups mask, if unicast set to zero*/  
  18.     addr_len = sizeof(st_peer_addr);  
  19.   
  20.     //设置select  
  21.     FD_ZERO(&st_read_set);  
  22.     FD_SET(s_nlm_socket, &st_read_set);  
  23.   
  24.     ret = select(s_nlm_socket+1, &st_read_set, NULL, NULL, &read_time_out);  
  25.     if(ret == -1)  
  26.     {  
  27.         //have some error.  
  28.         USE_DBG_OUT("select rcv some error %d", errno);  
  29.         goto err;  
  30.     }  
  31.     else if(ret == 0)  
  32.     {  
  33.         //超时退出  
  34.         TMP_DBG_OUT("rcv timeout.\n");  
  35.         *p_size = 0;  
  36.         goto out;  
  37.     }  
  38.     else  
  39.     {  
  40.         //接收消息  
  41.         ret = recvfrom(s_nlm_socket, &st_rcv_buf, sizeof(st_rcv_buf), 0,   
  42.             (struct sockaddr *)&st_peer_addr, &addr_len);  
  43.     }  
  44.      
  45.     if(ret == sizeof(st_rcv_buf) )  
  46.     {  
  47.         //收到消息了...  
  48.   
  49.     else  
  50.     {  
  51.         USE_DBG_OUT("rcv msg have some err. ret is %d, errno is %d\r\n", ret, errno);  
  52.         goto err;  
  53.     }  
  54.   
  55. out:      
  56.     return 0;  
  57. err:  
  58.     *p_size = 0;  
  59.     return -1;  
  60. }  



linux内核kobject事件处理详解 /*所有事件的名称列表*/ static const char *kobject_actions[] = { [KOBJ_ADD] = "add", [KOBJ_REMOVE] = "remove", [KOBJ_CHANGE] = "change", [KOBJ_MOVE] = "move", [KOBJ_ONLINE] = "online", [KOBJ_OFFLINE] 阅读详情

相关推荐

Linux Uevent和Netlink socket

Uevent是一种在内核空间和用户空间之间通信的机制,主要用于热插拔事件(hotplug)。编辑获取热插拔事件的源文件get_uevent.c#define _GNU_SOURCE#include <unistd.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <stddef.h> #include <str

Jackson_csdn的博客 5003

netlink---Linux下基于socket的内核和上层通信机制(上)

我最近有一个项目需求,需要在linux网卡驱动中加入一个自己的驱动,实现在内核态完成一些报文处理(这个过程可以实现一种零COPY的网络报文截获),对于复杂报文COPY下必要的数据交给用户态来完成(因为过于复杂的报文消耗CPU太大,会导致中断占用时间太长)。因此需要一种内核和用户态配合的通信机制,尝试了很多方式都不太理想,最后采用netlink+内存映射的模式很好的解决了这个问题。Netlink是一

squiffy的专栏 3823

Linux netlink socket使用总结

一、netlink机制的引入Linux提供了多种机制来完成内核空间与用户空间之间的数据交换,分别有内核启动参数、模块参数、sysfs、sysctl、系统调用、procfs、seq_file、debugfs、relayfs。其中,模块参数、sysfs、sysctl、procfs、seq_file、debugfs、relayfs是基于文件系统的通信机制,用于内核空间向用户空间输出信息;sysctl、系统

sprintwind的专栏 1万+

PF_NETLINK应用实例:NETLINK_KOBJECT_UEVENT的实现

udev的文档介绍:   1. dynamic replacement for  /dev。作为devfs的替代者,传统的devfs不能动态分配major和minor的值,而major和minor非常有限,很快就会用完了。 udev能够像DHCP动态分配IP地址一样去动态分配major和minor。   2. device naming。提供设备命名持久化的机制。传统设备命名方式不具直观

wangfeitaozhijia的专栏 1684

使用netlink机制在内核与应用程序之间通信

使用netlink机制在内核与应用程序之间通信前一段时间,在开发一个驱动程序的过程中,需要在驱动程序与应用程序之间进行通信。其中驱动程序在接收到一个硬件中断之后通知应用程序进行相应的处理。为 解决此类问题,驱动程序提供了几种机制:(1)使用copy_to_user/copy_from_user方法,缺点是通信响应时间过长(2)使用信 号,但是限于字符设备(3)使用netlink。在linu

OneOrZero的专栏 3762

Netlink Socket通信机制详解与实战指南

Netlink是Linux内核提供的一种IPC(进程间通信)机制,它允许用户空间进程与内核空间模块进行双向通信。这一机制特别适合于需要高效处理网络、内核数据或事件的场景。Netlink基于AF_NETLINK地址族,它使用标准的socket API进行操作,因此熟悉socket编程的开发者可以快速上手。Netlink支持多播消息,使得一个进程可以向多个目标进程广播消息,这在传统的UNIX domain socket中是不支持的。

weixin_35649491的博客 1659

netlink-Linux下基于socket的内核和上层通信机制

netlink---Linux下基于socket的内核和上层通信机制 需要在linux网卡驱动中加入一个自己的驱动,实现在内核态完成一些报文处理(这个过程可以实现一种零COPY的网络报文截获),对于复杂报文COPY下必要的数据交给用户态来完成(因为过于复杂的报文消耗CPU太大,会导致中断占用时间太长)。因此需要一种内核和用户态配合的通信机制,尝试了很多方式都不太理想,最后采用netlink+

胖胖哒键盘敲击兽 905

致远OA公文管理模块相关操作

致远oa协同办公系统 公文管理模板 相关操作

weixin_59666050的博客 4277

netlink---Linux下基于socket的内核和上层通信机制 (转)

需要在linux网卡 驱动中加入一个自己的驱动,实现在内核态完成一些报文处理(这个过程可以实现一种零COPY的网络报文截获),对于复杂报文COPY下必要的数据交给用户 态来完成(因为过于复杂的报文消耗CPU太大,会导致中断占用时间太长)。因此需要一种内核和用户态配合的通信机制,尝试了很多方式都不太理想,最后采用 netlink+内存映射的模式很好的解决了这个问题。Netlink是一种采用...

dfz87292的博客 146

GDI文字绘制和windows下opengl文字绘制小结

GDI绘制文字,要设置文字的属性,主要就是通过设置DC中的font对象来实现的。 font对象的创建可以由createfont()、createfontIndirect()来实现。 HFONT CreateFont( int nHeight, // height of font int nWidth, // average

T_W_S的专栏 5323

SAP 公司间库存调拨通过IDOC完成自动发票校验

本文仅用于SAP软件的应用与学习,不代表SAP公司。(注:文中所示截图来源SAP ERP软件,软件相应著作权归SAP所有。公司间采购时,通过SAP内部EDI 数据传输功能, 由销售方开的公司间发票自动触发采购方的发票校验。​欢迎扫码加如下微信,我会把大家拉到SAP PP学习群,随时欢迎跟我和其他SAP PP顾问一起交流和学习,如下图库存调拨订单,系统已经完成了发货方发货和收货方收货。

2402_84262664的博客 926

socket的内核和上层通信机制(netlink) -- linux内核

需要在linux网卡驱动中加入一个自己的驱动,实现在内核态完成一些报文处理(这个过程可以实现一种零COPY的网络报文截获),对于复杂报文COPY下必要的数据交给用户态来完成(因为过于复杂的报文消耗CPU太大,会导致中断占用时间太长)。因此需要一种内核和用户态配合的通信机制,尝试了很多方式都不太理想,最后采用netlink+内存映射的模式很好的解决了这个问题。Netlink是一种采用socket通信

《我是你的正能量》 3507

POI 写word,添加标题,表格,图片,自动生成目录,合并单元格

工程地址:https://github.com/zheng-chang-wei/word package com.example.demo1.poi; import org.apache.poi.xwpf.usermodel.XWPFDocument; import java.io.File; import java.io.FileOutputStream; public class ...

zheng_chang_wei的博客 6155

linux内核与用户空间通信机制——Netlink通信

可以参考这个链接的文章了解:https://blog.youkuaiyun.com/zhao_h/article/details/80943226 netlink是一种用于内核态和用户态进程之间进行数据传输的特殊的IPC机制。它的特点是: (1) 用户态采用socket风格的API (2)除了预定义的协议类型之外,支持自定义协议类型 (3)异步通讯 (4)支持消息组播 (5)全双工(特别是支持内核...

weixin_39094034的博客 4557

Arm Neoverse CMN-700 SLC内存系统与缓存分区技术解析

现代处理器架构中,缓存一致性协议与内存子系统设计直接影响系统性能。Arm Neoverse CMN-700采用的SLC(System Level Cache)通过16-way组相联设计实现高效数据缓存,其物理地址索引机制支持灵活的way分区配置。在软件可配置内存(OCM)模式下,SLC可作为独立内存空间使用,通过寄存器控制实现模式切换与区域锁定。缓存分区技术则通过请求源分类和way-based分配策略,满足实时性任务与吞吐量场景的不同需求。这些技术在5G基站、边缘计算等低延迟场景中具有重要应用价值,特别是C

weixin_30263073的博客 620

Supervisor 安装与使用

一、Supervisor 介绍 Supervisor 是一个用 Python 编写的进程管理工具,它可以用于监控和控制类 UNIX 操作系统上的多个进程。它是一个客户端/服务器系统,其中 Supervisor 的服务器端称为 supervisord,负责启动管理的子进程、响应客户端命令、重启崩溃或退出的子进程、记录子进程的 stdout 和 stderr 输出,以及处理子进程生命周期中的事件。客...

疯子丶pony的博客 3864

Linux 网络之netlink 简介

Linux 网络之netlink 简介以及一个简单使用demo

小立仔 1万+

安卓游戏存档修改全攻略:以《英雄迷宫冒险》为例(附避坑指南)

本文详细介绍了安卓游戏存档修改的全过程,以《英雄迷宫冒险》为例,涵盖基础认知、工具选择、实战修改及风险控制。通过十六进制编辑和UTF-8编码解析,玩家可以修改金钱、角色属性和物品数量等数据,同时提供了避坑指南和伦理考量,帮助玩家在享受修改乐趣的同时保持游戏体验的平衡。

weixin_29209801的博客 392

Linux设备模型uevent和Netlink通信机制

文章目录1.Netlink通信机制2. Linux设备文件系统3. sysfs 文件系统4.Uevent 1.Netlink通信机制 Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口。 Netlink 是一种特殊的 socket,它是 Linux 所特有的,类似于 BSD 中的AF_ROUTE 但又远比它的功能强大,目前在Linux 内核中使用netlink 进行应用与内核通信的应用很多; 包括: 路由 daemon(NETL

喜欢打篮球的普通人 3839

[TI板]MSPM0G3507——keil环境配置+烧录配置+vscode配置+空工程迁移+点灯+芯片解锁教程

本文介绍了MSPM0G3507开发环境的配置与烧录方法。主要内容包括:1)下载安装芯片支持包和SDK开发工具;2)通过串口或DAPLink两种方式实现程序烧录,详细说明了UniFlash软件的使用步骤和常见问题解决方法;3)简要提及工程迁移和LED点灯等基础操作。文章提供了完整的开发环境搭建指南,涵盖从软件安装到实际烧录的全过程,并附有相关工具下载链接和操作截图,帮助开发者快速上手MSPM0G3507开发。

qq_23220445的博客 1万+

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Linux 用户空间与内核空间的 Netlink 通信机制及实现

……

u013669912的博客 1138

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

linux 内核 :Netlink 原理分析

转:https://blog.youkuaiyun.com/luckyapple1028/article/details/50839395 Netlink 是一种IPC(Inter Process Commumicate)机制,它是一种用于内核与用户空间通信的机制,同时它也以用于进程间通信(Netlink 更多用于内核通信,进程之间通信更多使用Unix域套接字)。在一般情况下,用户态和内核态通信会使用传统的I...

老鹰不捉小鸡 4118

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

上一篇: Android电话系统之-rild
下一篇: socket编程
zzobin
博客等级 码龄18年 95粉丝 82原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值