用C语言编写Windows服务程序的五个步骤

2023-11-14

 
 
[ 翻译文档 本文适合初级读者 已阅读20305次 ]

用 C 语言编写 Windows 服务程序的五个步骤

原文:Yevgeny Menaker
翻译:Northtibet

下载源代码
原文出处:Five Steps to Writing Windows Services in C


摘要

  Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务。为了学习这种控制台应用程序的基础知识,C(不是C++)是最佳选择。本文将建立并 实现一个简单的服务程序,其功能是查询系统中可用物理内存数量,然后将结果写入一个文本文件。最后,你可以用所学知识编写自己的 Windows 服务。
  当初我写第一个 NT 服务时,我到 MSDN 上找例子。在那里我找到了一篇 Nigel Thompson 写的文章:“Creating a Simple Win32 Service in C++”,这篇文章附带一个 C++ 例子。虽然这篇文章很好地解释了服务的开发过程,但是,我仍然感觉缺少我需要的重要信息。我想理解通过什么框架,调用什么函数,以及何时调用,但 C++ 在这方面没有让我轻松多少。面向对象的方法固然方便,但由于用类对底层 Win32 函数调用进行了封装,它不利于学习服务程序的基本知识。这就是为什么我觉得 C 更加适合于编写初级服务程序或者实现简单后台任务的服务。在你对服务程序有了充分透彻的理解之后,用 C++ 编写才能游刃有余。当我离开原来的工作岗位,不得不向另一个人转移我的知识的时候,利用我用 C 所写的例子就非常容易解释 NT 服务之所以然。
  服务是一个运行在后台并实现勿需用户交互的任务的控制台程序。Windows NT/2000/XP 操作系统提供为服务程序提供专门的支持。人们可以用服务控制面板来配置安装好的服务程序,也就是 Windows 2000/XP 控制面板|管理工具中的“服务”(或在“开始”|“运行”对话框中输入 services.msc /s——译者注)。可以将服务配置成操作系统启动时自动启动,这样你就不必每次再重启系统后还要手动启动服务。
  本文将首先解释如何创建一个定期查询可用物理内存并将结果写入某个文本文件的服务。然后指导你完成生成,安装和实现服务的整个过程。


第一步:主函数和全局定义

首先,包含所需的头文件。例子要调用 Win32 函数(windows.h)和磁盘文件写入(stdio.h):

#include <windows.h>
#include <stdio.h>

接着,定义两个常量:

#define SLEEP_TIME 5000
#define LOGFILE "C://MyServices//memstatus.txt"

SLEEP_TIME 指定两次连续查询可用内存之间的毫秒间隔。在第二步中编写服务工作循环的时候要使用该常量。
LOGFILE 定义日志文件的路径,你将会用 WriteToLog 函数将内存查询的结果输出到该文件,WriteToLog 函数定义如下:

int WriteToLog(char* str)
{
FILE* log;
log = fopen(LOGFILE, "a+");
if (log == NULL)
return -1;
fprintf(log, "%s/n", str);
fclose(log);
return 0;
}

声明几个全局变量,以便在程序的多个函数之间共享它们值。此外,做一个函数的前向定义:

SERVICE_STATUS ServiceStatus; 
SERVICE_STATUS_HANDLE hStatus;

void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();

  现在,准备工作已经就绪,你可以开始编码了。服务程序控制台程序的一个子集。因此,开始你可以定义一个 main 函数,它是程序的入口点。对于服务程序来说,main 的代码令人惊讶地简短,因为它只创建分派表并启动控制分派机。

void main() 
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;

ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;

// 启动服务的控制分派机线程
StartServiceCtrlDispatcher(ServiceTable);
}

  一个程序可能包含若干个服务。每一个服务都必须列于专门的分派表中(为此该程序定义了一个 ServiceTable 结构数组)。这个表中的每一项都要在 SERVICE_TABLE_ENTRY 结构之中。它有两个域:

  • lpServiceName: 指向表示服务名称字符串的指针;当定义了多个服务时,那么这个域必须指定;
  • lpServiceProc: 指向服务主函数的指针(服务入口点);

  分派表的最后一项必须是服务名和服务主函数域的 NULL 指针,文本例子程序中只宿主一个服务,所以服务名的定义是可选的。
  服务控制管理器(SCM:Services Control Manager)是一个管理系统所有服务的进程。当 SCM 启动某个服务时,它等待某个进程的主线程来调用 StartServiceCtrlDispatcher 函数。将分派表传递给 StartServiceCtrlDispatcher。这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程,该线程运行分派表中每个服务 的 ServiceMain 函数(本文例子中只有一个服务)分派器还监视程序中所有服务的执行情况。然后分派器将控制请求从 SCM 传给服务。

注意:如果 StartServiceCtrlDispatcher 函数30秒没有被调用,便会报错,为了避免这种情况,我们必须在 ServiceMain 函数中(参见本文例子)或在非主函数的单独线程中初始化服务分派表。本文所描述的服务不需要防范这样的情况。

  分派表中所有的服务执行完之后(例如,用户通过“服务”控制面板程序停止它们),或者发生错误时。StartServiceCtrlDispatcher 调用返回。然后主进程终止。


第二步:ServiceMain 函数

Listing 1  
Listing 1: ServiceMain function
void ServiceMain(int argc, char** argv)
{
int error;

ServiceStatus.dwServiceType =
SERVICE_WIN32;
ServiceStatus.dwCurrentState =
SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted =
SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;

hStatus = RegisterServiceCtrlHandler(
"MemoryStatus",
(LPHANDLER_FUNCTION)ControlHandler);
if (hStatus == (SERVICE_STATUS_HANDLE)0)
{
// Registering Control Handler failed
return;
}
// Initialize Service
error = InitService();
if (error)
{
// Initialization failed
ServiceStatus.dwCurrentState =
SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
return;
}
// We report the running status to SCM.
ServiceStatus.dwCurrentState =
SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);

MEMORYSTATUS memory;
// The worker loop of a service
while (ServiceStatus.dwCurrentState ==
SERVICE_RUNNING)
{
char buffer[16];
GlobalMemoryStatus(&memory);
sprintf(buffer, "%d", memory.dwAvailPhys);
int result = WriteToLog(buffer);
if (result)
{
ServiceStatus.dwCurrentState =
SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus,
&ServiceStatus);
return;
}
Sleep(SLEEP_TIME);
}
return;
}

  Listing 1 展示了 ServiceMain 的代码。该函数是服务的入口点。它运行在一个单独的线程当中,这个线程是由控制分派器创建的。ServiceMain 应该尽可能早早为服务注册控制处理器。这要通过调用 RegisterServiceCtrlHadler 函数来实现。你要将两个参数传递给此函数:服务名和指向 ControlHandlerfunction 的指针。
  它指示控制分派器调用 ControlHandler 函数处理 SCM 控制请求。注册完控制处理器之后,获得状态句柄(hStatus)。通过调用 SetServiceStatus 函数,用 hStatus 向 SCM 报告服务的状态。
Listing 1 展示了如何指定服务特征和其当前状态来初始化 ServiceStatus 结构,ServiceStatus 结构的每个域都有其用途:

  • dwServiceType:指示服务类型,创建 Win32 服务。赋值 SERVICE_WIN32;
  • dwCurrentState:指定服务的当前状态。因为服务的初始化在这里没有完成,所以这里的状态为 SERVICE_START_PENDING;
  • dwControlsAccepted:这个域通知 SCM 服务接受哪个域。本文例子是允许 STOP 和 SHUTDOWN 请求。处理控制请求将在第三步讨论;
  • dwWin32ExitCode 和 dwServiceSpecificExitCode:这两个域在你终止服务并报告退出细节时很有用。初始化服务时并不退出,因此,它们的值为 0;
  • dwCheckPoint 和 dwWaitHint:这两个域表示初始化某个服务进程时要30秒以上。本文例子服务的初始化过程很短,所以这两个域的值都为 0。

  调用 SetServiceStatus 函数向 SCM 报告服务的状态时。要提供 hStatus 句柄和 ServiceStatus 结构。注意 ServiceStatus 一个全局变量,所以你可以跨多个函数使用它。ServiceMain 函数中,你给结构的几个域赋值,它们在服务运行的整个过程中都保持不变,比如:dwServiceType。
  在报告了服务状态之后,你可以调用 InitService 函数来完成初始化。这个函数只是添加一个说明性字符串到日志文件。如下面代码所示:

// 服务初始化
int InitService()
{
int result;
result = WriteToLog("Monitoring started.");
return(result);
}

  在 ServiceMain 中,检查 InitService 函数的返回值。如果初始化有错(因为有可能写日志文件失败),则将服务状态置为终止并退出 ServiceMain:

error = InitService(); 
if (error)
{
// 初始化失败,终止服务
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
// 退出 ServiceMain
return;
}

如果初始化成功,则向 SCM 报告状态:

// 向 SCM 报告运行状态 
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);

接着,启动工作循环。每五秒钟查询一个可用物理内存并将结果写入日志文件。

Listing 1 所示,循环一直到服务的状态为 SERVICE_RUNNING 或日志文件写入出错为止。状态可能在 ControlHandler 函数响应 SCM 控制请求时修改。
 

第三步:处理控制请求

Listing 2  
Listing 2: ControlHandler function
void ControlHandler(DWORD request)
{
switch(request)
{
case SERVICE_CONTROL_STOP:
WriteToLog("Monitoring stopped.");

ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
return;

case SERVICE_CONTROL_SHUTDOWN:
WriteToLog("Monitoring stopped.");

ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
return;

default:
break;
}

// Report current status
SetServiceStatus (hStatus, &ServiceStatus);

return;
}

  在第二步中,你用 ServiceMain 函数注册了控制处理器函数。控制处理器与处理各种 Windows 消息的窗口回调函数非常类似。它检查 SCM 发送了什么请求并采取相应行动。
  每次你调用 SetServiceStatus 函数的时候,必须指定服务接收 STOP 和 SHUTDOWN 请求。Listing 2 示范了如何在 ControlHandler 函数中处理它们。
  STOP 请求是 SCM 终止服务的时候发送的。例如,如果用户在“服务”控制面板中手动终止服务。SHUTDOWN 请求是关闭机器时,由 SCM 发送给所有运行中服务的请求。两种情况的处理方式相同:

  • 写日志文件,监视停止;
  • 向 SCM 报告 SERVICE_STOPPED 状态;

  由于 ServiceStatus 结构对于整个程序而言为全局量,ServiceStatus 中的工作循环在当前状态改变或服务终止后停止。其它的控制请求如:PAUSE 和 CONTINUE 在本文的例子没有处理。
  控制处理器函数必须报告服务状态,即便 SCM 每次发送控制请求的时候状态保持相同。因此,不管响应什么请求,都要调用 SetServiceStatus。


图一 显示 MemoryStatus 服务的服务控制面板


第四步:安装和配置服务

  程序编好了,将之编译成 exe 文件。本文例子创建的文件叫 MemoryStatus.exe,将它拷贝到 C:/MyServices 文件夹。为了在机器上安装这个服务,需要用 SC.EXE 可执行文件,它是 Win32 Platform SDK 中附带的一个工具。(译者注:Visaul Studio .NET 2003 IDE 环境中也有这个工具,具体存放位置在:C:/Program Files/Microsoft Visual Studio .NET 2003/Common7/Tools/Bin/winnt)。使用这个实用工具可以安装和移除服务。其它控制操作将通过服务控制面板来完成。以下是用命 令行安装 MemoryStatus 服务的方法:

sc create MemoryStatus binpath= c:/MyServices/MemoryStatus.exe

  发出此创建命令。指定服务名和二进制文件的路径(注意 binpath= 和路径之间的那个空格)。安装成功后,便可以用服务控制面板来控制这个服务(参见图一)。用控制面板的工具栏启动和终止这个服务。


图二 MemoryStatus 服务的属性窗口

  MemoryStatus 的启动类型是手动,也就是说根据需要来启动这个服务。右键单击该服务,然后选择上下文菜单中的“属性”菜单项,此时显示该服务的属性窗口。在这里可以修改启动类型以及其它设置。你还可以从“常规”标签中启动/停止服务。以下是从系统中移除服务的方法:

sc delete MemoryStatus

指定 “delete” 选项和服务名。此服务将被标记为删除,下次西通重启后,该服务将被完全移除。


第五步:测试服务

  从服务控制面板启动 MemoryStatus 服务。如果初始化不出错,表示启动成功。过一会儿将服务停止。检查一下 C:/MyServices 文件夹中 memstatus.txt 文件的服务输出。在我的机器上输出是这样的:

Monitoring started.
273469440
273379328
273133568
273084416
Monitoring stopped.

  为了测试 MemoryStatus 服务在出错情况下的行为,可以将 memstatus.txt 文件设置成只读。这样一来,服务应该无法启动。
  去掉只读属性,启动服务,在将文件设成只读。服务将停止执行,因为此时日志文件写入失败。如果你更新服务控制面板的内容,会发现服务状态是已经停止。
 

开发更大更好的服务程序

  理解 Win32 服务的基本概念,使你能更好地用 C++ 来设计包装类。包装类隐藏了对底层 Win32 函数的调用并提供了一种舒适的通用接口。修改 MemoryStatus 程序代码,创建满足自己需要的服务!为了实现比本文例子所示范的更复杂的任务,你可以创建多线程的服务,将作业划分成几个工作者线程并从 ServiceMain 函数中监视它们的执行。
 

作者简介
    Yevgeny Menaker 是一名有着超过5年经验开发人员,作家和 Linux 顾问。过去的三年,Yevgeny 专注于开发新的高级的 Internet 技术。他牵头编写了《Programming Perl in the .NET Environment》一书(Prentice-Hall)。此外,作为 Linux 顾问,他还在 Object Innovations 任职。Yevgeny Menaker 的联系方式是:jeka_books@hotmail.com

<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script> width="468" scrolling="no" height="60" frameborder="0" allowtransparency="true" hspace="0" vspace="0" marginheight="0" marginwidth="0" src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-4159669282587342&dt=1176703659781&lmt=1176703655&alt_color=FFFFFF&prev_fmts=728x90_as&format=468x60_as&output=html&url=http%3A%2F%2Fwww.vckbase.com%2Fdocument%2Fviewdoc%2F%3Fid%3D1474&color_bg=ECF8FF&color_text=6F6F6F&color_link=0000CC&color_url=008000&color_border=B4D0DC&ad_type=text_image&ref=http%3A%2F%2Fwww.google.cn%2Fsearch%3Fcomplete%3D1%26hl%3Dzh-CN%26q%3D%25E7%2594%25A8C%25E8%25AF%25AD%25E8%25A8%2580%25E7%25BC%2596%25E5%2586%2599Windows%25E6%259C%258D%25E5%258A%25A1%25E7%25A8%258B%25E5%25BA%258F%25E7%259A%2584%25E4%25BA%2594%25E4%25B8%25AA%25E6%25AD%25A5%25E9%25AA%25A4%26meta%3D&cc=9&u_h=768&u_w=1024&u_ah=734&u_aw=1024&u_cd=32&u_tz=480&u_his=1&u_java=true&u_nplug=6&u_nmime=15" name="google_ads_frame">

最新评论 [发表评论] [文章投稿] 查看所有评论 推荐给好友 打印

我也有同感,在ServiceMain里连接数据库总是失败 ( xqp1977 发表于 2006-9-8 11:02:00)
 
好文章,谢谢作者! ( zaodt 发表于 2006-3-31 12:37:00)
 
就是使用OLEDB中的CDataSource|CSession|CDynamicAccessor连接,代码如下:
::CoInitialize(NULL);
CDataSource db;
HRESULT hr = db.Open("MSDASQL","station","sa","");
if (FAILED(hr))
{
  _com_error err(hr);
  printf("[Test:ServiceMain] [%s]", err.ErrorMessage());
}
else
{
  printf("[Test:ServiceMain] OK!!");
  db.Close();
}
总是显示未指示的错误,是啥原因啊? ( Yu_Matrix 发表于 2005-5-23 17:05:00)
 
如果在ServiceMain里连接数据库为什么总是不成功呢? ( Yu_Matrix 发表于 2005-5-23 17:02:00)
 
.......................................................
More...


版权所有 © 2006 VC知识库 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用C语言编写Windows服务程序的五个步骤 的相关文章

  • 如何使用 saxon 将文档类型参数传递给 xslt?

    对于发送原子数据类型将使用类似 transformer SetParameter new QName customXml new XdmAtomicValue true 如何将 XML Node 作为参数从 C 传递给 XSLT 你能帮我么
  • Ruby 解释器嵌入到 C 代码中

    我只是尝试书中的一个简单例子 我有一个 sum rb 文件 class Summer def sum max raise Invalid maximum max if max lt 0 max max max 2 end end 还有一个
  • 如何从 Windows 批处理文件中的 ECHO 字符串中去除引号?

    我正在创建一个 Windows 批处理文件 但我必须 ECHO 一个大型复杂字符串 因此我必须在两端加上双引号 问题是引号也被回显到我正在写入的文件中 如何 ECHO 这样的字符串并去掉引号 UPDATE 我花了两天的时间研究这个问题 终于
  • 限制纬度和经度值的模数

    我有代表纬度和经度的双精度数 我可以轻松地将经度限制为 180 0 180 0 具有以下功能 double limitLon double lon return fmod lon 180 0 360 0 180 0 这是有效的 因为一端是排
  • 获取光标相对于控件的位置 - C#

    我想获取鼠标相对于鼠标指针所在控件的位置 这意味着当我将光标置于控件的起点 左上角 时 它应该给出 0 0 我正在使用以下代码 private void panel1 MouseMove object sender MouseEventAr
  • 堆栈独立的C/C++蓝牙API?

    我想知道是否有适用于 Windows XP Vista 7 x86 和 x64 的堆栈独立 C C 蓝牙 api 我的目标是创建连接并通过蓝牙发送 接收一些时间关键的数据 我的研究给了我以下选择以及这项任务的缺点 用于蓝牙的 Windows
  • 实体框架 5 不清除导航属性

    我在 Entity Framework 5 中遇到了这个奇怪的问题 我在其中一个实体中有一个导航属性 我想将其设置为null 但由于某种原因 该属性只有在我第二次调用该属性时才会被清除 using var db new Entities v
  • 为什么 CMake 不通过在定义该变量之前创建的 CMAKE_CXX_STANDARD 将语言标准编译标志添加到目标?

    我在用着cmake version 3 22 1 and c Ubuntu 11 3 0 1ubuntu1 22 04 11 3 0 以及非常简约的CMakeLists txt 我无法让 CMAKE 使用 C 20 Setting set
  • DLL 需要访问其应用程序的符号

    在 C 中 DLL 是否可以访问加载它的应用程序的某些符号 我有一个加载插件 dll 的应用程序 这些插件需要访问该应用程序的某些API 是否可以在不创建共享此 API 的新 DLL 的情况下实现此目的 函数指针结构适合这种情况吗 示例 主
  • 我需要一个树转储选项,该选项在当前的 gcc 版本中不再存在

    旧版本的 GCC 例如 4 0 2 或 4 1 2 有该选项 df see 用于调试程序或 GCC 的选项对于4 1 2 http gcc gnu org onlinedocs gcc 4 1 2 gcc Debugging Options
  • 如何使用 ASP.NET MVC 4.0 DonutOutputCache VaryByCustom 使缓存失效

    我正在为我的 ASP NET 应用程序使用 DevTrends MvcDonutCaching 包 它工作得很好 我目前遇到的一个问题是使我为子操作设置的 VaryByCustom 缓存无效 这是我用于 VaryByCustom 设置的一些
  • tcmalloc/jemalloc 和内存池之间有什么区别(以及选择的理由)?

    tcmalloc jemalloc是改进的内存分配器 还引入了内存池以更好地分配内存 那么它们之间有什么区别以及在我的应用中如何选择它们呢 这取决于您的程序的要求 如果您的程序有更多的动态内存分配 那么您 需要从可用的分配器中选择一个内存分
  • 如何定义 Swagger UI 参数的默认值?

    我已将 Swagger Swashbuckle 集成到 NET Core 2 2 API 项目中 一切都很好 我的要求纯粹是为了方便 考虑以下 API 方法 public Model SomeEstimate SomeRequest req
  • “sizeof”对不完整类型列表结构 C 的无效应用

    我正在尝试实现一种处理页面错误的替换算法 因此 我尝试使用 malloc 创建一个循环链表 但出现以下错误 无效的应用程序sizeof to incomplete typepageInMemory 以下是代码 typedef struct
  • System.Drawing.Icon 构造函数抛出“操作成功完成”异常

    在 Windows XP 计算机上 以下代码抛出 System ComponentModel Win32Exception 并显示消息 操作成功完成 System Drawing Icon icon new System Drawing I
  • 第一个随机数始终小于其余随机数

    我碰巧注意到 在 C 中 使用 std rand 方法调用的第一个随机数大多数时候都明显小于第二个随机数 关于 Qt 实现 第一个几乎总是小几个数量级 qsrand QTime currentTime msec qDebug lt lt q
  • 为 C++ 类播种 rand()

    我正在开发一个 C 类 它使用rand 在构造函数中 我真的希望这个班级在几乎所有方面都能照顾好自己 但我不知道在哪里播种rand 如果我播种rand 在构造函数中 每次构造我的对象类型的新实例时都会对其进行播种 因此 如果我按顺序创建 3
  • C中的pipe()和fork()

    我需要创建两个子进程 一个子进程需要运行命令 ls al 并将其输出重定向到下一个子进程的输入 而下一个子进程又将对其输入数据运行命令 sort r n k 5 最后 父进程需要读取该数据 已排序的数据 并将其显示在终端中 终端中的最终结果
  • Python 中的 C 指针算术

    我正在尝试将一个简单的 C 程序转换为 Python 但由于我对 C 和 Python 都一无所知 这对我来说很困难 我被 C 指针困住了 有一个函数采用 unsigned long int 指针并将其值添加到 while 循环中的某些变量
  • 如何使用 winrar 提取与 zip 文件同名的文件夹中的所有 zip 文件?

    我需要迭代一个文件夹 对于每个 zip 文件 我需要使用它的名称来提取它 也就是说 如果它是 test zip 那么它应该解压到 test 文件夹 同样 它应该迭代我的文件夹及其子文件夹并提取内容 我编写了下面的代码 但它没有使用 zip

随机推荐

  • Spring Cloud集成ELK完成日志收集实战(elasticsearch、logstash、kibana)

    简介 对于日志来说 最常见的需求就是收集 存储 查询 展示 开源社区正好有相对应的开源项目 logstash 收集 elasticsearch 存储 搜索 kibana 展示 我们将这三个组合起来的技术称之为ELK 所以说ELK指的是Ela
  • 深入浅出SQL(8)-使用Sequel pro 链接本地的mysql

    Authentication plugin caching sha2 password cannot be loaded 今天安装了Sequel pro 想连接本地的数据库 报了个错误 不能加载插件xxx 即对身份不能验证 打开偏好设置中S
  • Python破解wifi密码

    Python破解wifi密码 文章目录 Python破解wifi密码 1 下载破解字典口令集 2 引入密码本路径和WiFi名称 3 获取网卡信息并断开所有链接 4 连接验证 5 逐行读取文本内容并执行 6 破解开始 7 懒癌独家 1 下载破
  • vscode+php8+xdebug 无法安装composer

    1 下载composer 2 安装时出现提示 xdebug 的 远程服务无法连接 Xdebug Step Debug Time out connecting to debugging client waited 200 ms Tried l
  • java从远程url文件流读取文件并下载到本地

    java从远程url文件流读取文件 且下载到本地 写个循环可实现批量 import java io import java net HttpURLConnection import java net URL public class Fil
  • Linux 块设备驱动实验

    一 块设备驱动要远比字符设备驱动复杂得多 不同类型的存储设备又对应不同的驱动子系统 本章我们重点学习一下块设备相关驱动概念 不涉及到具体的存储设备 1 什么是块设备 块设备是针对存储设备的 比如 SD 卡 EMMC NAND Flash N
  • IDEA去除代码中的波浪线(黄色警告线)

    IDEA去除代码中的波浪线 黄色警告线 IDEA中为了减少一定量的重复代码 提醒开发人员注意 会在代码下面出现黄色警告线 但是有时候几行代码的重复没必要扔到一个统一的地方处理 这里还总是提醒 干扰视线 因此 这里根据个人习惯 还是关闭这个功
  • Item-Based Recommendations with Hadoop

    Mahout在MapReduce上实现了Item Based Collaborative Filtering 这里我尝试运行一下 安装Hadoop 从下载Mahout并解压 准备数据 下载1 Million MovieLens Datase
  • Codeforces Round #674 B. Symmetric Matrix(水题)

    题目地址 传送门 题目贴上 题意 给你n种 2x2的矩阵 并且每种矩阵可以无限次使用 问你是否能组成mxm的矩阵 新矩阵必须是严格按照主对角线对称矩阵 思路 首先给你的2x2矩阵 很明显我们不能拼成奇数长宽的矩阵 所以如果m为奇数 直接输出
  • Abstract Class(抽象类)& Abstract Method(抽象方法)

    java中的Abstract Class 抽象类 Abstract Method 抽象方法 Abstract Class 在面向对象的概念中 所有的对象都是通过类来描绘的 但是反过来 并不是所有的类都是用来描绘对象的 如果一个类中没有包含足
  • ZeroTier的planet文件格式分析

    C ProgramData ZeroTier One planet 文件格式 1个字节的类型 TYPE PLANET 1 TYPE MOON 127 8字节的ID 8字节的ts ZT C25519 PUBLIC KEY LEN 64字节的公
  • idea习惯配置记录

    idea 2021 git设置本地文件显示 链接 Settings Preferences Version Control Commit将Use non modal commit interface 取消选中的 use non modal
  • Android 11 锁屏界面 去掉下拉状态栏

    在目录 frameworks base packages SystemUI src com android systemui statusbar phone NotificationPanelViewController java 修改如下
  • 攻防世界-web- lottery

    lottery 41最佳Writeup由 清风77 提供WriteUP 收藏 反馈 难度 3 方向 Web 题解数 17 解出人数 5217 题目来源 XCTF 题目描述 暂无 题目附件 下载附件 题目场景 http 61 147 171
  • 2023哈工大软件工程考研

    0 考研成绩 初试成绩 395 政治 英语一 数学一 专业课 总分 71 76 130 118 395 复试成绩 251 综合测试118 面试133 排名 软专1 12 本部7 83 一校三区33 262 一切都拉下帷幕了 从去年二月到今年
  • Linux 用户、用户组 ( 添加、删除、修改 )

    Linux 使用者管理 http cn linux vbird org linux basic linux basic php part4 鸟哥官网 简体中文 http cn linux vbird org linux basic linu
  • STL实现动态维护有序数组

    使用 容器 vector 函数 v empty v lower bound v insert 代码实现
  • python + pandas读取含有不同空格的txt , csv,excel文件,以及跳过指定错误行数据

    使用pandas读取含有不同空格的txt csv excel文件 若txt文件全为float或者int时候 txt np loadtxt file 此仅适用于全数据类型的txt 文件 且文件内无空数据 txtDF pd DataFrame
  • CCIE理论-第十六篇-IPV6-GRE隧道+IPV6 OVER IPV4 隧道

    CCIE理论 第十六篇 IPV6 GRE隧道 IPV6 OVER IPV4 隧道 IPV6也写了好多篇章 后面还有两篇 一个IPV6的NAT 一个综合实验 那么就结束IPV6到MPLS了 其实还挺多的哈 差不多应该有10篇章都是在讲IPV6
  • 用C语言编写Windows服务程序的五个步骤

    翻译文档 本文适合初级读者 已阅读20305次 文档 代码 工具 用 C 语言编写 Windows 服务程序的五个步骤 原文 Yevgeny Menaker 翻译 Northtibet 下载源代码原文出处 Five Steps to Wri