博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Golang 实现Windows服务
阅读量:2087 次
发布时间:2019-04-29

本文共 5198 字,大约阅读时间需要 17 分钟。

文章目录

什么是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 ServiceTestsc 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 
#include
#include
#include
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) } }

转载地址:http://fplqf.baihongyu.com/

你可能感兴趣的文章
OpenCV学习——图像特效
查看>>
Spark源码剖析——Action操作、runJob流程
查看>>
分布式——缓存一致性(Redis、MySQL)
查看>>
Gminer 配置参数
查看>>
Linux学习笔记——20170802
查看>>
Linux学习笔记——20170803
查看>>
Linux学习笔记——20170804
查看>>
Linux学习笔记——20170805
查看>>
Linux学习笔记——20170807
查看>>
MySQL学习笔记——20170808
查看>>
MySQL学习笔记——20170809
查看>>
MySQL学习笔记——20170810
查看>>
MySQL学习笔记——20170811
查看>>
MySQL学习笔记——20170812
查看>>
Android内存溢出与优化(五)——防止static引用
查看>>
Scala学习笔记——20170817
查看>>
Scala学习笔记——20170818
查看>>
Scala学习笔记——20170819
查看>>
Scala学习笔记——20170820
查看>>
Python学习笔记——20170821
查看>>