我有一个测试程序,我想从命令行运行该程序的多个副本,并且我需要知道要启动的第一个程序实例。在飞镖,我做这有人向我建议如下:什么是在Go中实现信号量的最佳方式
RawServerSocket.bind("127.0.0.1", 8087)
如果失败了,那么我就知道另一个程序已“锁定”的端口。这为我解决了这个问题。当程序终止或套接字被明确关闭时,锁被释放。
如何在Go中获得类似的结果?
我有一个测试程序,我想从命令行运行该程序的多个副本,并且我需要知道要启动的第一个程序实例。在飞镖,我做这有人向我建议如下:什么是在Go中实现信号量的最佳方式
RawServerSocket.bind("127.0.0.1", 8087)
如果失败了,那么我就知道另一个程序已“锁定”的端口。这为我解决了这个问题。当程序终止或套接字被明确关闭时,锁被释放。
如何在Go中获得类似的结果?
你不说你正在使用的平台。如果你想要跨平台,那么打开本地套接字的解决方案非常简单。这里是你如何去做。
package main
import (
"log"
"net"
"time"
)
func main() {
ln, err := net.Listen("tcp", "127.0.0.1:9876")
if err != nil {
log.Fatal("Failed to get lock: ", err)
}
defer ln.Close()
log.Print("Started")
time.Sleep(time.Second * 10)
log.Print("Ending")
}
这样做不使用插座的跨平台的方式是相当困难和不幸将涉及两套代码一个类Unix系统,一个用于Windows。
注意,病毒检查不喜欢窗户打开监听socket程序...
的“UNIX办法”是创建的/ var内的pid文件/运行/ <名> .pid 这就是我们如何与码头工人https://github.com/dotcloud/docker/blob/master/docker/docker.go#L91 做,如果该文件存在,那么就意味着该程序已开始。
我不推荐使用bind方法,它将一个端口锁定为空,并且您无法确定其他程序是否未使用该端口。
我不认为锁定端口是一个问题 - 当然不是在测试环境中。冲突的问题可以通过程序来解决,该程序有一个默认的端口来锁定,但是检查一个环境变量来覆盖缺省值。你建议使用一个文件也可能是好的,但它对我没有吸引力。 –
如何使用os.OpenFile()
与os.CREATE | os.O_EXCL
标志?
file, err := os.OpenFile("lock", os.O_CREATE | os.O_EXCL | os.O_RDWR, 0400)
if err != nil {
// Someone else has acquired the lock.
}
defer file.Close()
defer os.Remove("lock") // Ignoring errors here!
我还没有编译或测试这一点,但它应该工作在任何情况下,你的想法...
当然,如果你的程序死在某种程度上没有删除文件,你有一个问题... – tchap
感谢您的答案。是的,我想要跨平台和理想的基于内存的解决方案(不是文件)。两套代码可以(我认为)。一个可以关闭/释放的全局对象是非常重要的。就病毒检查者而言,我想我必须穿过那座桥。我特别避免了基于文件的解决方案,但如果所有其他解决方案都失败了......我会尝试解决方案,但听起来好像它不是跨平台的。 –
上述解决方案可以在所有Go支持的平台上运行win/mac/linux/freebsd/etc。它可能会导致一个弹出窗口,可以允许一次,不会再打扰你... –