winsvc 包是对 golang.org/x/sys/windows 的封装,方便调用。底层调用的是sc命令来完成对服务的管理。
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, "%sn", `
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 .`)
}
// 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): %vn", *flagServiceName, *flagServiceDesc, err)
}
fmt.Printf("Donen")
return
}
// remove service
if *flagServiceUninstall {
if err := winsvc.RemoveService(*flagServiceName); err != nil {
log.Fatalln("removeService:", err)
}
fmt.Printf("Donen")
return
}
// start service
if *flagServiceStart {
if err := winsvc.StartService(*flagServiceName); err != nil {
log.Fatalln("startService:", err)
}
fmt.Printf("Donen")
return
}
// stop service
if *flagServiceStop {
if err := winsvc.StopService(*flagServiceName); err != nil {
log.Fatalln("stopService:", err)
}
fmt.Printf("Donen")
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: %vn", 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这个错误是权限的问题。本机是 win10,用的账号是 Administrator。
于是我在另一个电脑(win7)上做了同样的操作,发现是可以注册成功的。打开任务管理器,就可以找到go-srv服务,右键,启动服务,访问 localhost:8080正常。
尝试1:打开注册表
win + r --> regedit -->找到路径 HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionPoliciesSystem --> 将 EnableLUA 改成 0
发现还是不行,难道要重启吗,想了想,这个地方还是不能改,恢复为1。
于是我又打开了win7电脑,发现这个值是1。
尝试2:在同级目录下创建srv.bat
d: cd devphpmagooktrunkservergo-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 devphpmagooktrunkservergo-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.
效果是一样的。
serviceservice包也是一样的思路。
示例代码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。



