Skip to content

Instantly share code, notes, and snippets.

@quiiver
Created July 15, 2014 17:28
Show Gist options
  • Save quiiver/206d9e6127186d5975c2 to your computer and use it in GitHub Desktop.
Save quiiver/206d9e6127186d5975c2 to your computer and use it in GitHub Desktop.
Hot reloadable tcp client in go
package main
import (
"flag"
"fmt"
"log"
"net"
"os"
"os/signal"
"syscall"
"time"
)
var fds = flag.Int("fds", -1, "Fd you want to take over")
func send(conn net.Conn, fd uintptr) {
l, err := conn.Write([]byte("============= NEW CONN ===================\n"))
log.Printf("Wrote %d bytes to conn %v", l, conn)
if err != nil {
log.Printf("Could not write conn err: %v", err)
panic(err)
}
for {
conn.Write([]byte(fmt.Sprintf("hello from pid: %d, fd: %d\n", syscall.Getpid(), fd)))
time.Sleep(time.Second * 1)
}
}
func connect() (fd uintptr) {
if *fds == -1 {
log.Println("creating a new connection no fd to inherit")
conn, err := net.Dial("tcp", "localhost:3333")
if err != nil {
log.Panic(err)
}
tcp := conn.(*net.TCPConn)
file, err := tcp.File()
fd := file.Fd()
//fd, err = getFd(conn)
if err != nil {
log.Panic(fmt.Errorf("Error getting FD: %v", err))
}
go send(conn, fd)
return fd
}
fd = uintptr(*fds)
file := os.NewFile(fd, "tcp sock")
conn, err := net.FileConn(file)
if err != nil {
log.Panic(err)
}
log.Printf("inheriting connection. fd: %v, conn: %+v ", fd, conn)
go send(conn, fd)
return
}
func dup(oldfd int) (newfd int, err error) {
syscall.ForkLock.RLock()
defer syscall.ForkLock.RUnlock()
newfd, err = syscall.Dup(oldfd)
if err != nil {
return -1, err
}
return
}
func main() {
flag.Parse()
var fd uintptr
log.Println("fd to reconnect", *fds)
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, syscall.SIGHUP)
fd = connect()
log.Println("Got fd from connect: ", fd)
log.Println("waiting for signal")
log.Printf("kill -SIGHUP %d", syscall.Getpid())
sig := <-sigc
newFd, err := dup(int(fd))
if err != nil {
panic(err)
}
log.Println("Got signal:", sig)
args := append(os.Args, fmt.Sprintf("-fds=%d", newFd))
cmd := os.Args[0]
syscall.Exec(cmd, args, os.Environ())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment