概要
知らなかったので、忘れないうちにメモメモ。
先日、ncコマンドを使った通信確認について記載しました。
最近、以下の記事を知りました。
- Sockets In Your Shell
bash には、以下のようにしてTCPやUDPの通信する仕組みがあるんですね。知らなかった。。。
/dev/{tcp,udp}/ホスト/ポート
ローカルホストでudpでポート 32222 の場合は以下のようになります。
/dev/udp/127.0.0.1/32222
bash の man ページの REDIRECTION の章に以下の記載がありました。
/dev/tcp/host/port
If host is a valid hostname or Internet address, and port is an integer port number or service name, bash attempts to open the corresponding TCP socket.
/dev/udp/host/port
If host is a valid hostname or Internet address, and port is an integer port number or service name, bash attempts to open the corresponding UDP socket.
使う場合は、新しいファイルディスクリプタ (FD) を作ってやり取りします。0, 1, 2 は予約済みなので、通常は3ですね。
ちなみに
- 0
- 標準入力(STDIN)
- 1
- 標準出力(STDOUT)
- 2
- 標準エラー出力(STDERR)
です。
新しいディスクリプタ作る場合は exec コマンドを使って
$ exec 3<>/dev/udp/127.0.0.1/32222
という風にします。
あとは、ここに書き込んだり、ここから読み込んだりできます。
$ exec 3<>/dev/udp/127.0.0.1/32222 # write $ echo -e 'hello\n' >&3 # read $ cat <&3
試してみる
試してみるために、受け取った文字列を大文字にして返すエコーサーバみたいなのを用意。
エラー処理とかは手抜きして無しです。言語は何でもいいのですが、今回はGoで作りました。
package main import ( "fmt" "net" "strings" ) func main() { addr := &net.UDPAddr{ IP: net.ParseIP("127.0.0.1"), Port: 32222, } conn, _ := net.ListenUDP("udp", addr) for { buf := make([]byte, 1024) n, a, _ := conn.ReadFromUDP(buf) s := string(buf[:n]) fmt.Println(s) conn.WriteToUDP([]byte(strings.ToUpper(s)), a) } }
で、これを起動しておきます。
$ go run .
んで、別のターミナルで疎通確認をしてみます。
まずは、ファイルディスクリプタを作ります。今回はデータを送って、返答を受け取りたいので「読み書き両用」で開きます。
$ exec 3<>/dev/udp/127.0.0.1/32222
3<>
としている部分が「読み書き両用」の指定です。書き込み専用なら3>
、読み込み専用なら 3<
ですね。
データを送ってみます。
$ echo -e 'hello\n' >&3
そうすると、サーバ側のコンソールに hello
って表示されます。
サーバ側は、その後データを返送しているので、読み取ってみます。
$ cat <&3
HELLO
ちゃんと返ってきました。あとはそのままだとずっと cat が標準入力を待っているので Ctrl-c して終わり。
このやり方知っていると、最悪 nc コマンドすら入っていない環境でもなんとかなりますね。
参考情報
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場