Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Go编程语言中可靠地取消Unix域套接字的链接_Go_Signals_Unix Socket - Fatal编程技术网

如何在Go编程语言中可靠地取消Unix域套接字的链接

如何在Go编程语言中可靠地取消Unix域套接字的链接,go,signals,unix-socket,Go,Signals,Unix Socket,我有一个Go程序,在localhost:8080上托管一个简单的HTTP服务,因此我可以通过proxy\u-pass指令将我的公共nginx主机连接到它,作为反向代理来服务我的站点的部分请求。这一切都很好,没有问题 我想将Go程序转换为在Unix域套接字而不是本地TCP套接字上承载HTTP服务,以提高安全性并减少TCP不必要的协议开销 问题: 问题是,Unix域套接字一旦被bind()绑定到,即使在程序终止后,也无法重用。第二次(每次之后)我运行Go程序时,它退出时出现一个致命错误“地址已在使用

我有一个Go程序,在
localhost:8080
上托管一个简单的HTTP服务,因此我可以通过
proxy\u-pass
指令将我的公共
nginx
主机连接到它,作为反向代理来服务我的站点的部分请求。这一切都很好,没有问题

我想将Go程序转换为在Unix域套接字而不是本地TCP套接字上承载HTTP服务,以提高安全性并减少TCP不必要的协议开销

问题: 问题是,Unix域套接字一旦被
bind()
绑定到,即使在程序终止后,也无法重用。第二次(每次之后)我运行Go程序时,它退出时出现一个致命错误
“地址已在使用”

通常的做法是在服务器关闭时
取消链接()
Unix域套接字(即删除文件)。然而,这在围棋中很棘手。我的第一次尝试是在我的主func(见下文)中使用
defer
语句,但如果我用CTRL-C之类的信号中断进程,它将无法运行。我想这是意料之中的。令人失望,但并非出乎意料

问题:在服务器进程关闭时(正常或不正常)如何
取消套接字的链接()
是否有最佳做法

下面是我的
func main()
的一部分,它启动服务器侦听以供参考:

// Create the HTTP server listening on the requested socket:
l, err := net.Listen("unix", "/tmp/mysocket")
if err != nil {
    log.Fatal(err)
} else {
    // Unix sockets must be unlink()ed before being reused again.
    // Unfortunately, this defer is not run when a signal is received, e.g. CTRL-C.
    defer func() {
        os.Remove("/tmp/mysocket")
    }()

    log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
}

这是我使用的完整解决方案。我在问题中发布的代码是一个简化版本,用于明确的演示目的

// Create the socket to listen on:
l, err := net.Listen(socketType, socketAddr)
if err != nil {
    log.Fatal(err)
    return
}

// Unix sockets must be unlink()ed before being reused again.

// Handle common process-killing signals so we can gracefully shut down:
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
go func(c chan os.Signal) {
    // Wait for a SIGINT or SIGKILL:
    sig := <-c
    log.Printf("Caught signal %s: shutting down.", sig)
    // Stop listening (and unlink the socket if unix type):
    l.Close()
    // And we're done:
    os.Exit(0)
}(sigc)

// Start the HTTP server:
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
//创建要侦听的套接字:
l、 错误:=net.Listen(socketType,socketAddr)
如果出错!=零{
log.Fatal(错误)
返回
}
//在再次重用Unix套接字之前,必须取消其链接()。
//处理常见的进程终止信号,以便我们可以正常关闭:
sigc:=make(切换操作信号,1)
signal.Notify(sigc、os.Interrupt、os.Kill、syscall.SIGTERM)
go func(c通道操作信号){
//等待SIGINT或SIGKILL:

sig:=您可以使用信号处理程序结束主功能,并为其他任务生成单独的go例程。这样,您可以利用延迟机制,干净地处理所有(基于信号或非信号)关闭:

func main() {
    // Create the HTTP server listening on the requested socket:
    l, err := net.Listen("unix", "/tmp/mysocket")
    if err != nil {
        log.Fatal(err)
        return
    }
    // Just work with defer here; this works as long as the signal handling
    // happens in the main Go routine.
    defer l.Close()

    // Make sure the server does not block the main
    go func() {
        log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
    }()


    // Use a buffered channel so we don't miss any signals
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)

    // Block until a signal is received.
    s := <-c
    fmt.Println("Got signal:", s)

    // ...and exit, running all the defer statements
}
func main(){
//创建在请求的套接字上侦听的HTTP服务器:
l、 err:=net.Listen(“unix”,“tmp/mysocket”)
如果错误!=零{
log.Fatal(错误)
返回
}
//只需在这里使用DEBER;只要信号处理
//在主要的围棋程序中发生。
延迟l.关闭()
//确保服务器未阻止主服务器
go func(){
log.Fatal(http.service(l,http.HandlerFunc(indexHtml)))
}()
//使用缓冲通道,这样我们就不会错过任何信号
c:=制造(转换操作信号,1)
signal.Notify(c、os.Interrupt、os.Kill、syscall.SIGTERM)
//阻塞,直到收到信号。

s:=在现代围棋中,您可以使用
syscall.Unlink()
-docs:


@Tom谢谢。这个问题/答案已经有一年了,Go还在改进中,所以我想看看有没有新的/更好的出现。试试
os.Remove(“/tmp/mysocket”)
在第一行之前,它能工作吗?我用一个简单的信号处理程序使它工作得很好。现在还可以,因为用例非常简单,但我担心使用大量无法访问的开放资源进行更复杂的清理操作。
l.Close()如果侦听器的类型为
UnixListener
os,则
将取消套接字文件的链接。删除(socketAddr)
是冗余的。
import ( 
    "net"
    "syscall"
    ...
)

...


socketpath := "/tmp/somesocket"
// carry on with your socket creation:
addr, err := net.ResolveUnixAddr("unixgram", socketpath)
if err != nil {
    return err;
}

// always remove the named socket from the fs if its there
err = syscall.Unlink(socketpath)
if err != nil {
    // not really important if it fails
    log.Error("Unlink()",err)
}

// carry on with socket bind()
conn, err := net.ListenUnixgram("unixgram", addr);
if err != nil {
    return err;
}