当前位置: 首页 > news >正文

KRTS虚拟网络适配器和 Windows 连接

KRTS虚拟网络适配器和 Windows 连接

简介

在本教程中,我们将了解使用网络模块和 Windows NDIS 连接进行通信的几个用例。我们假设您已经熟悉网络模块的基本功能。

使用网络模块,可以创建多个虚拟网络适配器,这些适配器在内部与实际物理适配器或空适配器连接。此外,还可以打开与 Windows 网络堆栈连接的虚拟网络适配器。对于支持 Ethernet-over-EtherCAT (EoE) 的 EtherCAT 从站,也可以打开与数据包接口或 Windows 的连接。基于此功能,有几个用例。其中一些将在后面介绍。

创建虚拟网络适配器

如果我们想打开一个物理网络适配器卡,我们首先必须找到它。因此,我们将 KS_enumDevices 命名为 “NET”。有关详细信息,请参阅 如何查找设备 教程。

  int index;char pDeviceName[256];// ...ksError = KS_enumDevices("NET", index, pDeviceName, KSF_ACTIVE);

确定网络适配器的全名后,我们通过调用 KS_openNetworkAdapter 打开它。

  KSHandle hAdapter;ksError = KS_openNetworkAdapter(&hAdapter, pDeviceName, NULL, 0);

通过该调用,我们在内部创建一个物理网络适配器和一个附加到它的虚拟网络适配器。注意:每个虚拟网络适配器都有一个唯一的以太网地址。要将多个虚拟网络适配器连接到一个物理网络适配器,我们还使用 KS_openNetworkAdapterEx。通过这种方式,通过一个以太网端口将多个网络连接分组成为可能。

  KSHandle hFirstAdapter;ksError = KS_openNetworkAdapter(&hFirstAdapter, pDeviceName, NULL, 0);KSHandle hSecondAdapter;ksError = KS_openNetworkAdapterEx(&hSecondAdapter, hFirstAdapter, NULL, 0);KSHandle hThirdAdapter;ksError = KS_openNetworkAdapterEx(&hThirdAdapter, hFirstAdapter, NULL, 0);

如果要在没有物理设备的情况下连接多个虚拟网络适配器,则可以创建 null 适配器。因此,只需为 hConnection 句柄传递 null。

  KSHandle hFirstAdapter;ksError = KS_openNetworkAdapterEx(&hFirstAdapter, KS_INVALID_HANDLE, NULL, 0);KSHandle hSecondAdapter;ksError = KS_openNetworkAdapterEx(&hSecondAdapter, hFirstAdapter, NULL, 0);KSHandle hThirdAdapter;ksError = KS_openNetworkAdapterEx(&hThirdAdapter, hFirstAdapter, NULL, 0);

虚拟网卡应用场景

场景一:在没有物理设备的情况下建立 Windows 连接

也可以在 Kithara 实时环境和 Windows NDIS 网络堆栈之间创建连接。如果您有一个 Windows 控制应用程序,该应用程序旨在通过以太网连接到另一台 PC 上运行的实时系统,则这可能很有用。将其迁移到一台 PC 上装有 Windows 和 Kithara 的系统时,您可以使用此功能。

另一个优点是 Windows 应用程序可以与 Kithara 实时环境通信,而无需额外的网卡。

为了在 Windows NDIS 网络堆栈和 Kithara 实时环境之间建立连接,我们首先创建一个带有 KS_openAdapterEx 且没有连接句柄的空适配器。然后我们使用 KS_openAdapterEx 作为连接句柄,并使用标志 ‘KSF_PASS_THROUGH’。

  KSHandle hRealtimeAdapter;ksError = KS_openNetworkAdapterEx(&hRealtimeAdapter, KS_INVALID_HANDLE, NULL, 0);KSHandle hWindowsAdapter;ksError = KS_openNetworkAdapterEx(&hWindowsAdapter, hRealtimeAdapter, NULL, KSF_PASS_THROUGH);

你也可以这样写:

  KSHandle hWindowsAdapter;ksError = KS_openNetworkAdapterEx(&hWindowsAdapter、KS_INVALID、NULL、KSF_PASS_THROUGH);KSHandle hRealtimeAdapter;ksError = KS_openNetworkAdapterEx(&hRealtimeAdapter, hWindowsAdapter, NULL, 0);

备注:有关实现详细信息,请参阅示例"smp\NetworkUdpWindowsConnection"。

场景二:通过实时以太网适配器实现 Windows 通信的隧道

如果您只想使用一个物理网络适配器进行实时通信和 Windows 通信,则可以通过实时连接对优先级较低的帧进行隧道传输。

为此,我们首先创建一个实时网络适配器,然后使用 ‘KS_openNetworkAdapterEx’ 创建一个到 Windows 网络堆栈的网络桥,并将实时适配器和 ‘KSF_PASS_THROUGH’ 作为参数传递。

  KSHandle hRealtimeAdapter;ksError = KS_openNetworkAdapter( &hRealtimeAdapter, pDeviceName, NULL, 0);KSHandle hWindowsAdapter;ksError = KS_openNetworkAdapterEx(&hWindowsAdapter,hRealtimeAdapter,0, KSF_PASS_THROUGH);

备注:有关实现详细信息,请参阅示例 ‘smp\NetworkEthernetTunnel’。

场景三:使用 Kithara 功能的非实时 Windows 硬件

在这里插入图片描述

在某些情况下,您希望直接从 Kithara 实时环境访问的网络设备,我们可以通过 Windows 重定向通信。因此,有必要在 Windows 网络环境中创建一个网桥,将连接到 Kithara 和您要使用的设备连接起来。这甚至可以是 WLAN 适配器。

可以创建网桥。例如,在 Windows 7 上,使用"开始"→控制面板→"网络和共享中心"→更改适配器设置。标记要桥接的网络适配器,然后单击鼠标右键。然后选择 “Bridge Connections”。注意:通信通过 Windows 重定向,并非实时通信。

在示例代码中,我们通过 Windows 网络设备打开 Kithara EtherCAT 主站。首先,我们创建一个 null 适配器,其中包含到 Windows 网络堆栈的网桥。接下来,我们创建一个实时适配器,该适配器具有到 null 适配器的网桥。最后但并非最不重要的一点是,我们使用 Kithara 实时环境适配器创建一个 EtherCAT 主站。

  KSHandle hWindowsAdapter;ksError = KS_openNetworkAdapterEx(&hWindowsAdapter, null, NULL, KSF_PASS_THROUGH);KSHandle hRealtimeAdapter;ksError = KS_openNetworkAdapterEx(&hRealtimeAdapter, hWindowsAdapter, NULL, 0);KSHandle hMaster;ksError = KS_createEcatMaster(&hMaster, hRealtimeAdapter, null, null, 0);

场景四:连接到 EoE EtherCAT 从站

Ethernet-over-EtherCAT (EoE) 是 EtherCAT 工业以太网标准的邮箱协议。这样,EtherCAT 从站和 EtherCAT 主站之间的以太网连接通过 EtherCAT 通信建立隧道。例如,有像 Beckhoff EL6601 这样的从站,它有一个以太网交换机端口,或者其他有 Web 服务器来解决配置问题。

要将这些 EoE 端点连接到 Windows 网络堆栈,只需将 EtherCAT 从站句柄传递给 KS_openNetworkAdapterEx 并带有标志 ‘KSF_PASS_THROUGH’ 即可。

  KSHandle hRealtimeAdapter;ksError = KS_openAdapter(&hRealtimeAdapter, pDeviceName, NULL, 0);// ...KSHandle hMaster;ksError = KS_createEcatMaster(&hMaster, hRealtimeAdapter, ...);KSHandle hEoESlave;ksError = KS_createEcatSlave(&hEoESlave, ...);// ...KSHandle hEoeAdapter;ksError = KS_openNetworkAdapterEx(&hEoeAdapter, hEoESlave, NULL, KSF_PASS_THROUGH);

备注:有关实现的详细信息,请参阅示例 ‘smp\EtherCATEoeWindowsConnection’。

项目示例

通过UD实现内核层与Windows通信
  1. 应用层主要代码
#include "NetworkUdpWindowsConnection.h"#pragma pack(push, 8)#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif#define _WINSOCK_DEPRECATED_NO_WARNINGS#if !(defined(_MSC_VER) && (_MSC_VER <= 1500))
#include <winsock2.h>
#endif
#include <stdio.h>
#include <stdlib.h>#pragma pack(pop)#pragma comment(lib, "Ws2_32.lib")//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
//   注意这是Demo版本
// 
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!const char pCustomerNumber[] = "DEMO";//--------------------------------------------------------------------------------------------------------------
// 消息接收的回调线程
//--------------------------------------------------------------------------------------------------------------KSError __stdcall _recvThread(void* pArgs) {KSError ksError = KS_OK;CallBackData* pData = (CallBackData*)pArgs;while (!pData->finished_) {//----------------------------------------------------------------------------------------------------------// 等待内核层事件通知//----------------------------------------------------------------------------------------------------------ksError = KS_waitForEvent(pData->hEvent_,                        0,                                     0);                                     if (ksError != KS_OK)return ksError;int length;byte pBuf[2048];while (KS_getPipe(pData->hPipe_, &pBuf, 2048, &length, 0) == KS_OK) {outputTxt((char*)pBuf);}}outputTxt("Thread has been finished.");return ksError;
}//--------------------------------------------------------------------------------------------------------------
// Ip输出
//--------------------------------------------------------------------------------------------------------------char* ipv4ToString(char* dest, uint addr) {addr = KS_ntohl(addr);sprintf(dest, "%d.%d.%d.%d", addr >> 24 & 0xFF,addr >> 16 & 0xFF,addr >>  8 & 0xFF,addr >>  0 & 0xFF);return dest;
}//--------------------------------------------------------------------------------------------------------------
// 项目入口
//--------------------------------------------------------------------------------------------------------------void runSample() {outputTxt("***** Kithara example program 'NetworkUdpWindowsConnection' *****");#if defined(_MSC_VER) && (_MSC_VER <= 1500)outputTxt("Sorry, your compiler does not support this example.");return;#elseKSError ksError;ksError = KS_openDriver(pCustomerNumber);                      if (ksError) {outputErr(ksError, "KS_openDriver", "Unable to open the driver!");return;}KSSystemInformation systemInfo;                      systemInfo.structSize = sizeof(KSSystemInformation);  ksError = KS_getSystemInformation(&systemInfo,                             KSF_NO_FLAGS);                          if (ksError != KS_OK) {outputErr(ksError, "KS_getSystemInformation", "Unable to get system information to distinguish bitsize !");KS_closeDriver();return;}KSHandle hKernel;ksError = KS_loadKernel(&hKernel,                         systemInfo.isSys64Bit ?                 "NetworkUdpWindowsConnection_64.dll" :           "NetworkUdpWindowsConnection_32.dll",               NULL,                                    NULL,                                    KSF_KERNEL_EXEC);                      if (ksError != KS_OK) {outputErr(ksError, "KS_loadKernel", "Unable to load DLL! Is the DLL in the search path?");KS_closeDriver();return;}//------------------------------------------------------------------------------------------------------------// 创建共享内存//------------------------------------------------------------------------------------------------------------CallBackData* pAppPtr;CallBackData* pSysPtr;ksError = KS_createSharedMem((void**)&pAppPtr,                     (void**)&pSysPtr,                        "NetworkUdpWindowsConnectionData",      sizeof(CallBackData),                    0);                                   if (ksError != KS_OK) {outputErr(ksError, "KS_createSharedMem", "Failed to allocate shared memory");KS_closeDriver();return;}strcpy(pAppPtr->msg_, "Hello Windows");//------------------------------------------------------------------------------------------------------------//  创建一个空的网络适配器//------------------------------------------------------------------------------------------------------------KSHandle hAdapter;ksError = KS_openNetworkAdapterEx(&hAdapter,                                KS_INVALID_HANDLE,                       NULL,                                    0);                                      if (ksError != KS_OK) {outputErr(ksError, "KS_openNetworkAdapterEx", "Failed to open adapter");KS_closeDriver();return;}//------------------------------------------------------------------------------------------------------------// 配置网络适配器//------------------------------------------------------------------------------------------------------------KSIPConfig config;KS_makeIPv4(&config.localAddress,   192, 168,   6,  100);KS_makeIPv4(&config.subnetMask,     255, 255, 255,   0);KS_makeIPv4(&config.gatewayAddress, 0,     0,   0,   0);char ipString[16];outputTxt("Current local IP address:       ", false);outputTxt(ipv4ToString(ipString, config.localAddress));outputTxt("Current subnet mask:            ", false);outputTxt(ipv4ToString(ipString, config.subnetMask));outputTxt("Current gateway address:        ", false);outputTxt(ipv4ToString(ipString, config.gatewayAddress));outputTxt("Otherwise change the example!");outputTxt(" ");ksError = KS_execNetworkCommand(hAdapter,                                KS_NETWORK_SET_IP_CONFIG,                 &config,                                  0);                                      if (ksError != KS_OK) {outputErr(ksError, "KS_execNetworkCommand", "Failed to set IP config");KS_closeDriver();return;}//------------------------------------------------------------------------------------------------------------// 基于空的网络适配器,创建一个用于和Window通信的网络适配器//------------------------------------------------------------------------------------------------------------KSHandle hWinAdapter;ksError = KS_openNetworkAdapterEx(&hWinAdapter,                            hAdapter,                               NULL,                                    KSF_PASS_THROUGH);                if (ksError != KS_OK) {outputErr(ksError, "KS_openNetworkAdapterEx", "Failed to open adapter");KS_closeDriver();return;}waitTime(100 * ms);//------------------------------------------------------------------------------------------------------------// 创建一个管道,用于传输内核数据//------------------------------------------------------------------------------------------------------------ksError = KS_createPipe(&pAppPtr->hPipe_,                        "NetworkUdpWindowsConnectionPipe",          1500,                                     100,                                     NULL,                                    KSF_MESSAGE_PIPE);                     if (ksError != KS_OK) {outputErr(ksError, "KS_createPipe", "Unable to create pipe!");KS_closeDriver();return;}//------------------------------------------------------------------------------------------------------------// 创建事件//------------------------------------------------------------------------------------------------------------ksError = KS_createEvent(&pAppPtr->hEvent_,                       "NetworkUdpWindowsConnectionEvent",           0);                                      if (ksError != KS_OK) {outputErr(ksError, "KS_createEvent", "Unable to create finish event!");KS_closeDriver();return;}//------------------------------------------------------------------------------------------------------------// 创建线程//------------------------------------------------------------------------------------------------------------ksError = KS_createThread(_recvThread,                             pAppPtr,                                 NULL);                                   if (ksError != KS_OK) {outputErr(ksError, "KS_createThread", "Unable to create the thread!");KS_closeDriver();return;}KSHandle hCallBack;ksError = KS_createKernelCallBack(&hCallBack,                             hKernel,                                 "_callBack",                             pSysPtr,                                KSF_DIRECT_EXEC,                        0);                                     if (ksError != KS_OK) {outputErr(ksError, "KS_createCallBack", "Failed to create callback");KS_closeDriver();return;}//------------------------------------------------------------------------------------------------------------// 指定套接字地址//------------------------------------------------------------------------------------------------------------const ushort USER_PORT = 0xaaaa;KSSocketAddr socketAddr;socketAddr.family = KS_FAMILY_IPV4;socketAddr.port = KS_htons(USER_PORT);socketAddr.address[0] = config.localAddress;//------------------------------------------------------------------------------------------------------------// 打开UDP通信,注意使用的网络适配器是主适配器,而非Windows适配器//------------------------------------------------------------------------------------------------------------ksError = KS_openSocket(&pAppPtr->hSocket_,                     hAdapter,                                &socketAddr,                            KS_PROTOCOL_UDP,                          KSF_CLIENT);                             if (ksError != KS_OK) {outputErr(ksError, "KS_openSocket", "Failed to open socket");KS_closeDriver();return;}//------------------------------------------------------------------------------------------------------------// 创建UDP消息回调//------------------------------------------------------------------------------------------------------------pAppPtr->remoteAddr.family = KS_FAMILY_IPV4;pAppPtr->remoteAddr.port = KS_htons(0);KS_makeIPv4(pAppPtr->remoteAddr.address, 0, 0, 0, 0);//------------------------------------------------------------------------------------------------------------// 安装接收消息回调//------------------------------------------------------------------------------------------------------------pAppPtr->finished_ = false;ksError = KS_installSocketHandler(pAppPtr->hSocket_,                      KS_SOCKET_RECV,                         hCallBack,                               0);                                      if (ksError != KS_OK) {outputErr(ksError, "KS_installSocketHandler", "Failed to install receive handler");KS_closeDriver();return;}//------------------------------------------------------------------------------------------------------------// 注意在执行一下代码,之前需要配置虚拟网卡的IP地址// 方法: 控制面板-》网络和 Internet-》网络连接//       找到虚拟网卡右击属性 -网络- Internet协议属性4(IPv4),设置IP地址和掩码//------------------------------------------------------------------------------------------------------------outputTxt("Please adjust the IP-config of the Windows Adapter to 192.168.6.200 and subnet mask 255.255.255.0");inputTxt("Press <enter> when ready");outputTxt(" ");//------------------------------------------------------------------------------------------------------------// 创建一个Windows socket 模拟应用层或者外部应用与内核通信//------------------------------------------------------------------------------------------------------------WSADATA wsaData = {0};WSAStartup(MAKEWORD(2, 2), &wsaData);outputTxt("open Windows socket");outputTxt(" ");SOCKET sock = INVALID_SOCKET;sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (sock == INVALID_SOCKET) {outputErr(KSERROR_INTERNAL, "socket", "Failed to create socket");KS_closeDriver();return;}//------------------------------------------------------------------------------------------------------------// 发送消息给内核层//------------------------------------------------------------------------------------------------------------sockaddr_in recvAddr;recvAddr.sin_family = AF_INET;recvAddr.sin_port = htons(USER_PORT);recvAddr.sin_addr.s_addr = inet_addr("192.168.6.100");outputTxt("sendto Windows socket");outputTxt(" ");int result = sendto(sock, "Hello Kithara", 14, 0, (SOCKADDR*)&recvAddr, sizeof(recvAddr));if (result == SOCKET_ERROR) {outputErr(KSERROR_UNKNOWN, "sendto", "Failed to send to socket");KS_closeDriver();return;}//------------------------------------------------------------------------------------------------------------// 内核层回复消息到应用层//------------------------------------------------------------------------------------------------------------outputTxt("recvFrom Windows socket");outputTxt(" ");sockaddr_in senderAddr;char pBuf[64];int fromLen = sizeof(sockaddr_in);result = recvfrom(sock, pBuf, 14, 0, (SOCKADDR*)&senderAddr, &fromLen);if (result == SOCKET_ERROR) {outputErr(KSERROR_UNKNOWN, "recvfrom", "Failed to receive from socket");KS_closeDriver();return;}outputTxt((char*)pBuf);//------------------------------------------------------------------------------------------------------------// 退出//------------------------------------------------------------------------------------------------------------outputTxt("close Windows socket");outputTxt(" ");closesocket(sock);WSACleanup();pAppPtr->finished_ = true;ksError = KS_setEvent(pAppPtr->hEvent_);                       if (ksError != KS_OK)outputErr(ksError, "KS_setEvent", "Setting event failed!");waitTime(500 * ms);ksError = KS_closeSocket(pAppPtr->hSocket_);                      if (ksError != KS_OK)outputErr(ksError, "KS_closeSocket", "Unable to close Socket!");ksError = KS_closeNetwork(hWinAdapter, 0);                        if (ksError != KS_OK)outputErr(ksError, "KS_closeNetwork", "Unable to close Adapter!");ksError = KS_closeNetwork(hAdapter, 0);                           if (ksError != KS_OK)outputErr(ksError, "KS_closeNetwork", "Unable to close Adapter!");ksError = KS_removeCallBack(hCallBack);                             if (ksError != KS_OK)outputErr(ksError, "KS_removeCallBack", "Unable to remove the callback!");ksError = KS_closeEvent(pAppPtr->hEvent_);                      if (ksError != KS_OK)outputErr(ksError, "KS_closeEvent", "Unable to close event!");ksError = KS_removePipe(pAppPtr->hPipe_);                        if (ksError != KS_OK)outputErr(ksError, "KS_removePipe", "Unable to remove the pipe!");ksError = KS_freeSharedMem(pAppPtr);                               if (ksError != KS_OK)outputErr(ksError, "KS_freeSharedMem", "Unable to remove shared memory!");ksError = KS_freeKernel(hKernel);                               if (ksError != KS_OK)outputErr(ksError, "KS_freeKernel", "Unable to free the kernel!");ksError = KS_closeDriver();if (ksError != KS_OK)outputErr(ksError, "KS_closeDriver", "Unable to close the driver!");waitTime(500 * ms);outputTxt("End of program 'NetworkUdpWindowsConnection'.");#endif // defined(_MSC_VER) && (_MSC_VER <= 1200)
}
  1. 内核层主要代码

#include "NetworkUdpWindowsConnection.h"//------ 回调------
extern "C" KSError __declspec(dllexport) __stdcall _callBack(void* pArgs, void* pContext) {CallBackData* pData = (CallBackData*)pArgs;KSError ksError;int length;do {//----------------------------------------------------------------------------------------------------------// 接收UDP消息回调//----------------------------------------------------------------------------------------------------------ksError = KS_recvFromSocket(pData->hSocket_,                      &pData->remoteAddr,                     pData->pBuf_,                          2048,                                  &length,                                0);                                   if (ksError && KSERROR_CODE(ksError) != KSERROR_NO_DATA_AVAILABLE)return ksError;if (ksError == KS_OK) {//--------------------------------------------------------------------------------------------------------// 通知应用层//--------------------------------------------------------------------------------------------------------ksError = KS_putPipe(pData->hPipe_,                        &pData->pBuf_,                       length,                            NULL,                                0);                                  //--------------------------------------------------------------------------------------------------------// 通过事件唤醒线程接收数据//--------------------------------------------------------------------------------------------------------KS_setEvent(pData->hEvent_);                              KS_sendToSocket(pData->hSocket_,                            &pData->remoteAddr,                            pData->msg_,                                   14,                                            NULL,                                         0);                                           }} while (ksError == KS_OK);return KS_OK;
}#define WIN32_LEAN_AND_MEAN
#pragma pack(push, 8)
#include <windows.h>
#pragma pack(pop)BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID pReserved) {return TRUE;
}
  1. 共享内存结构体

. 注意一字节对齐

#include "../_KitharaSmp/_KitharaSmp.h"struct CallBackData {KSHandle hSocket_;KSSocketAddr remoteAddr;KSHandle hEvent_;KSHandle hPipe_;byte pBuf_[2048];char msg_[14];bool finished_;
};

补充配置IP地址:
在这里插入图片描述
运行效果:
在这里插入图片描述
也可使用其他网络工具与内核通信:
在这里插入图片描述

相关文章:

  • 相机、镜头参数详解以及相关计算公式
  • 2024 Python3.10 系统入门+进阶(十六):正则表达式
  • Eureka原理实践:构建高可用、可扩展的微服务架构
  • 《C++无锁编程:解锁高性能并发的新境界》
  • day01——登录功能
  • npm切换到淘宝镜像
  • Redis——缓存
  • 15年408-数据结构
  • Stable Diffusion绘画 | SDXL模型的优缺点及模型推荐
  • 【linux进程】进程状态僵尸进程孤儿进程
  • 遥感影像-语义分割数据集:山体滑坡数据集详细介绍及训练样本处理流程
  • 计算机毕业设计 基于Hadoop的智慧校园数据共享平台的设计与实现 Python 数据分析 可视化大屏 附源码 文档
  • 防火墙详解(二)通过网页登录配置华为eNSP中USG6000V1防火墙
  • Git 使用方法
  • 揭秘 Elasticsearch 集群架构,解锁大数据处理神器
  • Angular Elements 及其运作原理
  • dva中组件的懒加载
  • flask接收请求并推入栈
  • webpack+react项目初体验——记录我的webpack环境配置
  • 检测对象或数组
  • 设计模式 开闭原则
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 小程序button引导用户授权
  • 携程小程序初体验
  • 自制字幕遮挡器
  • 《码出高效》学习笔记与书中错误记录
  • HanLP分词命名实体提取详解
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #Lua:Lua调用C++生成的DLL库
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (LLM) 很笨
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (计算机网络)物理层
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (三十五)大数据实战——Superset可视化平台搭建
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (转)Sublime Text3配置Lua运行环境
  • (转)甲方乙方——赵民谈找工作
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .a文件和.so文件
  • .FileZilla的使用和主动模式被动模式介绍
  • .JPG图片,各种压缩率下的文件尺寸
  • .NET 读取 JSON格式的数据
  • .net 无限分类
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .NET6 命令行启动及发布单个Exe文件
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • .NET开源项目介绍及资源推荐:数据持久层
  • @Autowired @Resource @Qualifier的区别