何故かは分かりませんが、golang は net.TCPListener の file descriptor が export されていません。
通常は特に問題ないのですが、graceful restart を実装しようとした場合に困ったことになります。
ちなみに func (l *TCPListener) File() (f *os.File, err error)
というのもありますが、これは file descriptor を複製するので graceful restart には使えません。(同じポートを Listen することになるため、複製の時点で bad file descriptor になる)
どうやって取るかというと、伝家の宝刀 reflect パッケージを使います。
package main
import (
"fmt"
"net"
"reflect"
)
func main() {
addr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:8000")
if err != nil {
panic(err)
}
listener, err := net.ListenTCP("tcp", addr)
if err != nil {
panic(err)
}
fdValue := reflect.Indirect(reflect.Indirect(reflect.ValueOf(listener)).FieldByName("fd"))
fd := uintptr(fdValue.FieldByName("sysfd").Int())
fmt.Println(fd)
}
この unexported なフィールドから取得するの、すごく気持ち悪いんですが他に方法ないんですかね。。。