winsvc

winsvcgolang.org/x/sys/windowssc

windows服务是脱离于登录用户而存在的,因此必须由管理员来管理。

// 管理员身份

// 注册服务
sc create ServiceName binpath="/path/to/exe"

// 删除服务
sc delete ServiceName

// 启动服务
sc start ServiceName

// 停止服务
sc stop ServiceName

示例代码

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/chai2010/winsvc"
)

var (
	appPath string

	flagServiceName = flag.String("service-name", "hello-winsvc", "Set service name")
	flagServiceDesc = flag.String("service-desc", "hello windows service", "Set service description")

	flagServiceInstall   = flag.Bool("service-install", false, "Install service")
	flagServiceUninstall = flag.Bool("service-remove", false, "Remove service")
	flagServiceStart     = flag.Bool("service-start", false, "Start service")
	flagServiceStop      = flag.Bool("service-stop", false, "Stop service")
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `
Usage:
  hello [options]...

Options:
`)
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, "%s\n", `
Example:
  # run hello server
  $ go build -o hello.exe hello.go
  $ hello.exe

  # install hello as windows service
  $ hello.exe -service-install

  # start/stop hello service
  $ hello.exe -service-start
  $ hello.exe -service-stop

  # remove hello service
  $ hello.exe -service-remove

  # help
  $ hello.exe -h

Report bugs to <chaishushan{AT}gmail.com>.`)
	}

	// change to current dir
	var err error
	if appPath, err = winsvc.GetAppPath(); err != nil {
		log.Fatal(err)
	}
	if err := os.Chdir(filepath.Dir(appPath)); err != nil {
		log.Fatal(err)
	}
}

func main() {
	flag.Parse()

	// install service
	if *flagServiceInstall {
		if err := winsvc.InstallService(appPath, *flagServiceName, *flagServiceDesc); err != nil {
			log.Fatalf("installService(%s, %s): %v\n", *flagServiceName, *flagServiceDesc, err)
		}
		fmt.Printf("Done\n")
		return
	}

	// remove service
	if *flagServiceUninstall {
		if err := winsvc.RemoveService(*flagServiceName); err != nil {
			log.Fatalln("removeService:", err)
		}
		fmt.Printf("Done\n")
		return
	}

	// start service
	if *flagServiceStart {
		if err := winsvc.StartService(*flagServiceName); err != nil {
			log.Fatalln("startService:", err)
		}
		fmt.Printf("Done\n")
		return
	}

	// stop service
	if *flagServiceStop {
		if err := winsvc.StopService(*flagServiceName); err != nil {
			log.Fatalln("stopService:", err)
		}
		fmt.Printf("Done\n")
		return
	}

	// run as service
	if !winsvc.InServiceMode() {
		log.Println("main:", "runService")
		if err := winsvc.RunAsService(*flagServiceName, StartServer, StopServer, false); err != nil {
			log.Fatalf("svc.Run: %v\n", err)
		}
		return
	}

	// run as normal
	StartServer()
}

func StartServer() {
	log.Println("StartServer, port = 8080")
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "winsrv server", time.Now())
	})
	http.ListenAndServe(":8080", nil)
}

func StopServer() {
	log.Println("StopServer")
}

go get -u github.com/chai2010/winsvc
go build

// 注册服务
go-srv.exe -service-name="go-srv" -service-desc="test go service" -service-install
2021/11/30 17:06:29 installService(go-srv, test go service): Access is denied.

// 移除服务
go-srv.exe -service-name="go-srv" -service-remove
......
Access is denied
go-srvlocalhost:8080

尝试1:

打开注册表

win + r --> regedit -->找到路径 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System  --> 将 EnableLUA 改成 0

发现还是不行,难道要重启吗,想了想,这个地方还是不能改,恢复为1。

于是我又打开了win7电脑,发现这个值是1。

尝试2:

srv.bat
d:
cd dev\php\magook\trunk\server\go-srv
go-srv.exe -service-name="go-srv" -service-desc="test go service" -service-install
cmd

右键,以管理员身份运行。

输出

2021/12/01 11:42:41 installService(go-srv, test go service): A system shutdown is in progress.

这次不是权限的问题了,看来在win10中,administrator账户并不是管理员,或者说他也不具备全部的权限,或者说这个电脑被前面的同事做了什么设置。

A system shutdown is in progress.

尝试3:

win + Q --> 输入 cmd --> 右键
> d:
> cd dev\php\magook\trunk\server\go-srv
> go-srv.exe -service-name="go-srv" -service-desc="test go service" -service-install
2021/12/01 11:42:41 installService(go-srv, test go service): A system shutdown is in progress.

效果是一样的。

service

service

示例代码

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/kardianos/service"
)

var serviceConfig = &service.Config{
	Name:        "go-srv",
	DisplayName: "go-srv",
	Description: "test go service",
}

func main() {

	// 构建服务对象
	prog := &Program{}
	s, err := service.New(prog, serviceConfig)
	if err != nil {
		log.Fatal(err)
	}

	// 用于记录系统日志
	logger, err := s.Logger(nil)
	if err != nil {
		log.Fatal(err)
	}

	if len(os.Args) < 2 {
		err = s.Run()
		if err != nil {
			logger.Error(err)
		}
		return
	}

	cmd := os.Args[1]

	if cmd == "install" {
		err = s.Install()
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("安装成功")
	}
	if cmd == "uninstall" {
		err = s.Uninstall()
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("卸载成功")
	}

	// install, uninstall, start, stop 的另一种实现方式
	// err = service.Control(s, os.Args[1])
	// if err != nil {
	// 	log.Fatal(err)
	// }
}

type Program struct{}

func (p *Program) Start(s service.Service) error {
	log.Println("开始服务")
	go p.run()
	return nil
}

func (p *Program) Stop(s service.Service) error {
	log.Println("停止服务")
	return nil
}

func (p *Program) run() {
	// 此处编写具体的服务代码
}
go get -u github.com/kardianos/service
go build
win + Q --> 输入 cmd --> 右键
go-srv.exe install
2021/12/01 16:11:43 A system shutdown is in progress.

还是一样的错误。

到这里,不得不重启了!!

重启之后果然就好了。接着测试。

// 管理员身份运行cmd
打开任务管理器,点到服务栏

> go-srv.exe -service-name="go-srv" -service-desc="test go service" -service-install
  Done
但是并没有多出一个 go-srv 服务,当然重新打开任务管理器就可以看到了。但是我们可以调用启动命令来使其展示出来。

> go-srv.exe -service-name="go-srv" -service-start
看到了 go-srv 服务,且正在运行。

> go-srv.exe -service-name="go-srv" -service-remove
发现没有什么效果,服务依然在运行着。

> go-srv.exe -service-name="go-srv" -service-stop
停止服务,同时发现,服务被移除了,所以应该先 stop 再来 remove。