ここ に記載されている問題のトラブルシューティング中に、私は本当に基本的なものを試しました:UDP経由で非常に基本的なnetcat接続をセットアップしようとしましたが、期待どおりに機能していないことに気付きました。
以下のTCPの図のように、UDPの場合はウィンドウ2に入力したときと同じ出力がウィンドウ1にエコーされると予想しました。代わりに、UDPの場合はウィンドウ1に出力がありません。 。
私は私のラップトップでDebian Jessieを実行しており、次のキャプチャフィルターを使用してWiresharkを実行しています。
udp and not (port 123 or port 5353 or port 1900)
1つのターミナルウィンドウで、次のコマンドを実行してTCPテストを開始しました。
$ nc -l 6900
2番目のターミナルウィンドウで、次のコマンドを実行しました。
$ nc localhost 6900
ウィンドウ2で、「1」と入力してEnterキーを押し、次に「2」と入力してEnterキーを押し、最後にCtrl + Dを押して終了しました。
「one」でEnterキーを押すと、ウィンドウ1に「one」がエコーされます。「two」でEnterキーを押すと、ウィンドウ1に「two」がエコーされます。Ctrl+ Dを押すと、両方のnetcatインスタンスが終了し、戻りました。プロンプトに。
これは、TCP接続を問題なく実行できることを示しています。次に、UDPを試しました。
ウィンドウ1:
$ nc -l -u 6900
ウィンドウ2:
$ nc -u localhost 6900
それはおかしいです。 「1」と入力してEnterキーを押し、次に「2」キーを押してEnterキーを押すと、ウィンドウ2のプロンプトに自動的に戻ります。
ウィンドウ1に、出力が表示されません。
ウィンドウ1で-v
を使用して再試行しました。
$ nc -v -l -u 6900
Listening on [0.0.0.0] (family 0, port 6900)
ウィンドウ2で-v
を使用して再試行したときはおかしいです。
$ nc -v -u localhost 6900
$
Netcatが実行されなかったようなものです。私はすぐにプロンプトに戻りました。
更新:localhost
を127.0.0.1
に置き換えると、進捗があります。
ウィンドウ1でリッスンする「サーバー」を使用します。
$ nc -v -l -u 6900
one
two
three
「1」、「2」、「3」と入力すると、ウィンドウ2からエコーされた出力を取得できました。
$ nc -u 127.0.0.1 6900
one
two
three
^C
-v
は、上記と同じであるため、まだ不可解です。
MacOSを使用して、私は別の結論に達しました。キーはIPv6です。 localhost
はIPv6とIPv4の両方に解決されます。ただし、次のコマンドラインでは、nc
がIPv4でリッスンします。
nc -l -u 6900
結果:
$ lsof -n -i:6900
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nc 63923 fuzzy 3u IPv4 0xad7f669b928a178b 0t0 UDP *:6900
これを使用して「接続」すると、次のようになります。
nc -u localhost 6900
...実際にはIPv6に接続します。 127.0.0.1
を使用する場合、使用しません。
ただし、UDPはコネクションレスであるため、接続しません。そのため、接続のリモートエンドが実際に存在するかどうかを知る方法はありません。そのため、IPv4にフォールバックする必要があることを検出できません。メッセージは送信されますが、それらのメッセージをリッスンするものはありません。
送信すると、次のことが確認できます。
$ tcpdump -i lo0 udp port 6900
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
00:46:37.543273 IP6 localhost.54473 > localhost.6900: UDP, length 6
TCPを使用すると、IPv6で接続を試み、これが機能していないと判断して、IPv4で再試行します。
$ tcpdump -i lo0 port 6900
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
00:50:21.495107 IP6 localhost.64306 > localhost.6900: Flags [SEW], seq 1432891337, win 65535, options [mss 16324,nop,wscale 5,nop,nop,TS val 766376063 ecr 0,sackOK,eol], length 0
00:50:21.495136 IP6 localhost.6900 > localhost.64306: Flags [R.], seq 0, ack 1432891338, win 0, length 0
00:50:21.495231 IP localhost.64307 > localhost.6900: Flags [S], seq 307818799, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 766376063 ecr 0,sackOK,eol], length 0
00:50:21.495283 IP localhost.6900 > localhost.64307: Flags [S.], seq 4254625238, ack 307818800, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 766376063 ecr 766376063,sackOK,eol], length 0
00:50:21.495295 IP localhost.64307 > localhost.6900: Flags [.], ack 1, win 12759, options [nop,nop,TS val 766376063 ecr 766376063], length 0
00:50:21.495306 IP localhost.6900 > localhost.64307: Flags [.], ack 1, win 12759, options [nop,nop,TS val 766376063 ecr 766376063], length 0
nc
にIPv4の使用を強制できます。
nc -4u localhost 6900
最後の結論を参照してください。
結果を説明できます。私はDebianではなくKubuntuを使用していますが、それでも要点は共通していると思います。何が起こるかを完全に理解するには、TCPケースを分析してから、UDPと比較することをお勧めします。
私の研究を再現したい場合は、私がそう言ったり、それ自体で終了したりしない限り、nc
を終了したり殺したりしないでください。私が言うとき、nc
sを殺します。それは非常に重要です。完全な答えを読んだ後、あなたはこれのポイントを理解するでしょう。
この分析には、複数の端末(またはtmux
、またはscreen
)が必要です。
最初に、以前のすべてのnc
プロセスを取り除きます。
killall nc
リスニングプロセスを実行します。
nc -l 6900
lsof -i :6900
の出力を調べます。あなたのnc
はそこでリスニングプロセスとしてリストされています。
接続プロセスを実行します。
nc localhost 6900
lsof -i :6900
の出力を調べます。 2つのnc
sは、established接続の終わりです。
最初のnc
はもうリッスンしていないので、secondリッスンプロセスを実行できます。
nc -l 6900
および秒接続プロセス:
nc localhost 6900
nc
が実行されているすべてのコンソールに何かを入力します(ヒットすることを忘れないでください) Enter 毎回)。 2つの別々の接続があることがわかります。必要に応じて、3番目のものを確立できます。
lsof -i :6900
をもう一度確認してください。 2つの(以前の)リスニングnc
sは同じポート6900
を使用しますが、もう一方の端のnc
sは異なるため、2つの接続は混在しませんポート。パケットが6900
ポートに到着すると、カーネルはこの他のポートをチェックし、(以前の)リスニングnc
sのどれがそれを受信するかを決定します。
追加の(ペアになっていない)接続nc
を実行できます。
nc localhost 6900 || echo fail
そしてそれはすぐに失敗します。
まだ2つの別々の接続が確立されています。すべてのペアの1つのnc
をで終了します Ctrl + C または Ctrl + D また、対応する両端も終了します。これは、TCPがコネクション型であるためです。接続がいずれかの端から正常に終了すると、それに応じて反応できるように、もう一方の端に通知されます。この場合はnc
ただ終了します。
重要:
killall nc
次のコマンドを順番に実行し、それぞれを個別のコンソールで実行します。また、それぞれの後にlsof -i :6900
をチェックして、何が起こるかを確認してください。コマンドは次のとおりです。
nc -ul 6900
nc -u localhost 6900
最初に何かを入力します(「リスニング」)nc
(ヒット Enter);チェックlsof -i :6900
; 2番目のnc
に何かを入力します(ヒット Enter); lsof -i :6900
をもう一度確認して、変更を記録します。
次に、別のペアを(別々のコンソールで)準備します。
nc -ul 6900
nc -u localhost 6900
いくつかの文字列をやり取りして、機能するかどうかを確認します。 1つのnc
をで終了します Ctrl + C ((Ctrl + D 動作しません)、他のnc
(対応する端)がまだ実行されていることに注意してください。 「接続」の反対側は、「接続」がいつ「終了」したかを知りません。 lsof
で確認できるように、データが流れ始めるまで、「接続」が「確立」されていることがわかりません。
UDPはコネクションレス型であり、これが主な違いであるため、ここでいくつかの単語を引用します。
これまでのところ、すべてが機能しているはずです。物事がうまくいかなかったときに、以前の結果を説明し始める時が来ました。
重要:
killall nc
「リスニング」を準備するnc
:
nc -ul 6900
lsof -i :6900
を確認してください。出力は次のようになります。
… UDP *:6900
「接続」を準備するnc
:
nc -u localhost 6900
lsof -i :6900
を確認してください。出力例(54766
は異なる場合があります):
… UDP *:6900
… UDP localhost:54766->localhost:6900
2番目のnc
から最初のnc
にデータを渡します。 lsof -i :6900
を確認してください:
… UDP localhost:6900->localhost:54766
… UDP localhost:54766->localhost:6900
2番目のnc
を Ctrl + C。もう一度lsof -i :6900
:
… UDP localhost:6900->localhost:54766
つまり、最初のnc
は、「接続」の反対側のポート54766
にのみ「通信」します。 3番目のnc
に接続しようとすると:
nc -u localhost 6900
おそらく、その側で別のランダムなポートを選択します。それを試してみてください。このnc
が終了する前に、質問で行ったのと同じように、(約)2行を「渡す」ことができます。
(注:このwireshark
はICMPパケットが原因で終了します。 this を参照してください。lsof
でパケットをキャプチャすることができます。)
ただし、適切なポートを強制することができます(nc
出力に合わせて54766
を変更してください)。
nc -up 54766 localhost 6900
そして、この4番目のnc
はデータを渡すことができます!最初のnc
では違いはわかりません。 2番目のnc
が決して終了されなかったかのようになります。
続行する前に、4番目のnc
を終了します。最初のものを実行したままにします。
-v
オプション最後の謎は、なぜnc -v -u localhost 6900
がすぐに終了したのか?
上記の例では、4つのX
sがありました。
私のKubuntunc -uv …
では、2番目の場合、おそらく接続をプローブするために、いくつかのnc
文字を送信します。このため、それが3番目の場合、(約)2行の外部入力が失敗する必要はなく、すぐに失敗します。 最初のnc
がまだ実行されている場合は、次を試してください:
nc -uv localhost 6900
失敗するはずです。繰り返しますが、適切なポートを強制することができ、上記の例の4番目X
のように機能します。
nc -uvp 54766 localhost 6900
これを呼び出すと、最初のnc
のコンソールにnc
- sが出力されているのがわかります。
killall nc
あなたが持っていたように見えます( "listening")nc
これはすでに「接続」の反対側の特定のポートに関連付けられていました。 else)少なくとも1つのパケットを正常に送信した。他のnc
sが、他のポートを使用しようとしたため、この最初のポートと通信できませんでした。
localhost
を127.0.0.1
に置き換えると、進捗があります
無関係です。この場合、killall nc
の後で行ったように、クリーンに始めたばかりだと思います。