Golang 实现Windows服务
什么是windows服务
Windows 服务是主要用于服务器环境而长期运行的应用程序, 这类程序不需要有用户界面或者任何模拟输出。 任何的用户消息通常都是记录在Windows 事件日志里。Windows Service可以在操作系统启动的时候开始,一直在后台运行,当有需要时也可以手动启动,我们可以通过管理工具里面的服务进行统一管理。
当系统启动完毕后,Windows服务并不需要通过登陆页面后才能启动,即使用户注销登录也不会停止,通常不和用户产生交互。
而我们启动一般的exe文件却要先登陆Windows后才能启动它,通常还有一个用户界面,命令行或者是GUI界面,通常由用户手动启动和停止。
如何注册windows服务
手工注册Windows服务得用得到windows下cmd命令(管理员身份)
注册服务 [ServiceTest]:
sc create ServiceTest binpath="/path/to/exe"
启动服务:
sc start ServiceTest
停止服务、删除服务:
sc stop ServiceTest
sc delete ServiceTest
用vc++实现windows服务:
首先要初始化 SERVICE_TABLE_ENTRY 结构体数组,
SERVICE_TABLE_ENTRY serviceEntryTable[2];
serviceEntryTable[0].lpServiceName = L"ServiceTest";
serviceEntryTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceWorker;
serviceEntryTable[1].lpServiceName = NULL;
serviceEntryTable[1].lpServiceProc = NULL;
其中,ServiceTest 是要注册的服务的名称,ServiceWorker 是服务主工作函数。
通过调用 StartServiceCtrlDispatcher(serviceEntryTable)
,把调用进程的主线程转换为控制分派器,启动一个新线程运行分派表中的 ServiceWorker 函数。
然后,准备ServiceWorker函数,
ServiceWorker 服务程序的主运行函数,除了与普通函数执行任务之外,
它还需要完成一个工作:通过调用 RegisterServiceCtrlHandler
向服务控制管理器注册控制函数。
并且调用 向 SCM(服务控制管理器)报告当前的状态。
SERVICE_STATUS serviceStatus;
serviceStatus.dwServiceType = SERVICE_WIN32;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
serviceStatusHandle = ::RegisterServiceCtrlHandler(L"ServiceTest", ServiceCtrlHandler);
其中 ServiceCtrlHandler
是控制处理函数,它接收 SCM 发来的控制命令,并且处理命令和回馈状态。
最后,准备控制处理函数 ServiceCtrlHandler
控制处理函数必须在30秒内返回,否则 SCM 会返回一个错,如果是一个比较耗时的操作,则需要另启一个线程来进行处理。
void WINAPI ServiceCtrlHandler(DWORD request)
{
switch (request)
{
case SERVICE_CONTROL_STOP:
serviceRunning = false;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
break;
case SERVICE_CONTROL_SHUTDOWN:
serviceRunning = false;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
break;
default:
break;
}
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
完整示例代码
该示例实现了一个简单的windows服务程序,
每秒钟在C盘目录下打印一个数字。
#include <string>
#include <fstream>
#include <iostream>
#include <windows.h>
using namespace std;
bool serviceRunning = false;
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle;
void WINAPI ServiceWorker(int argc, char** argv);
void WINAPI ServiceCtrlHandler(DWORD request);
void ServiceLog(string str)
{
fstream fout("c:/service_log.txt", ios::out | ios::app);
if (!fout) {
return;
}
fout << str << endl;
}
void WINAPI ServiceWorker(int argc, char** argv)
{
serviceStatus.dwServiceType = SERVICE_WIN32;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
serviceStatusHandle = ::RegisterServiceCtrlHandler(L"ServiceTest", ServiceCtrlHandler);
if (0 == serviceStatusHandle)
{
ServiceLog("RegisterServiceCtrlHandler failed");
return;
}
ServiceLog("RegisterServiceCtrlHandler success");
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
// 工作内容,每隔一秒钟输出一个数字
int num = 0;
serviceRunning = true;
while (serviceRunning)
{
ServiceLog(to_string(num++));
Sleep(1000);
}
ServiceLog("Service Stopped");
}
void WINAPI ServiceCtrlHandler(DWORD request)
{
switch (request)
{
case SERVICE_CONTROL_STOP:
serviceRunning = false;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
break;
case SERVICE_CONTROL_SHUTDOWN:
serviceRunning = false;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
break;
default:
break;
}
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
void main()
{
SERVICE_TABLE_ENTRY serviceEntryTable[2];
serviceEntryTable[0].lpServiceName = L"ServiceTest";
serviceEntryTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceWorker;
serviceEntryTable[1].lpServiceName = NULL;
serviceEntryTable[1].lpServiceProc = NULL;
StartServiceCtrlDispatcher(serviceEntryTable);
}
Golang 实现 Windows 服务
Go语言有第三方封装好的库,可以用很少的代码实现一个Windows服务,相比C++方便了很多。
package main
import (
"log"
"os"
"time"
"github.com/kardianos/service"
)
type program struct{}
func (p *program) Start(s service.Service) error {
go p.run()
return nil
}
func (p *program) run() {
for {
time.Sleep(time.Second)
log.Println("running")
}
}
func (p *program) Stop(s service.Service) error {
return nil
}
func init() {
f, err := os.Create("d:/gowinservice.txt")
if err != nil {
log.Fatal(err)
}
log.SetOutput(f)
}
func main() {
svcConfig := &service.Config{
Name: "GoService",
DisplayName: "GoServiceDis",
Description: "windows service form golang",
}
prg := &program{}
s, err := service.New(prg, svcConfig)
if err != nil {
log.Fatal(err)
}
if len(os.Args) > 1 {
if os.Args[1] == "install" {
s.Install()
log.Println("服务安装成功")
return
}
if os.Args[1] == "remove" {
s.Uninstall()
log.Println("服务卸载成功")
return
}
}
if err = s.Run(); err != nil {
log.Fatal(err)
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现