I have a test program where I want to run multiple copies of the program from the command-line, and I need to know the first instance of the program to start. In Dart, I do the following which someone suggested to me :
RawServerSocket.bind("127.0.0.1", 8087)
If that fails, then I know that another program has "locked" the port. That solves the problem sufficiently well for me. The lock is released when the program terminates or when the socket is explicitly closed.
How can I achieve a similar result in Go?
You don't say which platform you are using. If you want to be cross platform then the solution of opening a local socket is very easy. Here is how you do it in 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")
}
A cross platform way of doing this without using a socket is quite hard unfortunately and would involve two sets of code one for Unix like systems and one for windows.
Note that virus checkers don't like programs opening listening sockets on windows...
The 'unix way' would be to create a pid file within /var/run/<name>.pid This is how we do it with Docker https://github.com/dotcloud/docker/blob/master/docker/docker.go#L91 If the file exists, then it means the program is already started.
I would not recommend to use the bind method, it lock a port for nothing and you can't be sure that an other program is not using the port.
What about using os.OpenFile()
with os.CREATE | os.O_EXCL
flag?
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!
I haven't compiler or tested this, but it should work and in any case, you get the idea...