最近、 Goで書かれたアプリケーションサーバが起動しない! ->原因: .env ファイルが欠けていた というドタバタがありました。
結局Goと関係ないですが、この時、 「あまりGoに慣れてないのでGoの問題かと…」「DockerまだよくわかってなくてDockerの問題かと…」 というような声があったのて、あえてGoで検証してみようと思ったわけです。
さて、Goでサーバサイドのシステムを作る場合、 直接的・間接的(echoなどのフレームワーク経由で)に、netパッケージの機能を使うことになると思います。 そして多くの場合、設定ファイルや.env・環境変数などでGo外部からListenするポート番号を指定することになります。
ではうっかり、ポート番号が空になってしまった場合、どのような挙動になるのでしょうか。 ポートの指定は string なので ":" となっている場合、ということですね。
ということでさっそく、次のようなコードで実験してみましょう。
main.go
package main
import (
"fmt"
"net"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world.")
})
listener, err := net.Listen("tcp", ":")
if err != nil {
panic(err)
}
fmt.Println("Port:", listener.Addr().(*net.TCPAddr).Port)
panic(http.Serve(listener, nil))
}
go run main.go
おそらく、怪しげなポート番号が表示されるはずです。 Ctl+C で停止して、何度か実行してみると、ポート番号は起動するたびに変化していることがわかります。 しかもポート番号の数字が大きめです。
これはいわゆる「Port 0」の挙動ですね。Go 関係ありません。 0番は使用できないことになっているので、動的ポート番号領域(つまり 49152 以上)が割り振られるというやつです。
たとえば echo の場合、起動時にこういうメッセージバナーが表示されます。
____ __
/ __/___/ / ___
/ _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.1.5
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
O\
⇨ http server started on [::]:8080
ここで起動中のポート番号が表示されるので、 「あれ?起動してるのに接続できない!なんで!?」 ということがあった場合には、 まず想定通りのポートで立ち上がっているかを確認してみた方がいいですね。 プロキシが間にある場合や、Dockerで立ち上げている場合はとくに。