これは概念的な質問に似ています。いくつかの説明が必要です。
今日、私はいくつかのソケットプログラミングのことを学び、 Beej's Guide to Network Programming に基づいて簡単なチャットサーバーとチャットクライアントを書きました。 (チャットサーバーはクライアントメッセージを受信し、他のすべてのクライアントにメッセージを送信します)
チャットサーバー をコピーして、独自の チャットクライアント を作成しました。
チャットクライアントは、stdin
入力をサーバーに送信し、サーバーからソケットデータを印刷するプログラムにすぎません。
後で、ガイドがtelnet
を使用してサーバーに接続できると説明していることに気付きました。私が試してみましたが、うまくいきました。
私はTelnetに慣れていなかったので、長い間、正確には何なのかわかりませんでした。
だから今私の経験は私を混乱させます:
Telnetは単純なTCP send/echoプログラムではありませんか?プロトコルであることが特別な理由は何ですか? ?ダムチャットクライアントプログラムで[アプリケーション]プロトコルが作成されません。
ウィキペディアから Communication_protocol :
電気通信では、通信プロトコルはrulesのシステムであり、通信システムの2つ以上のエンティティがあらゆる種類の物理的なバリエーションを介して情報を送信できるようにします。量。
Telnetはどのような規則を作成しますか? telnet Host port
、開いているTCP生の入出力用のストリームソケットですか?それは規則ではありません。
Telnetは RFC 854 で定義されています。プロトコル(およびその他のプロトコル)を構成するものは、一連のルール/制約です。そのようなルールの1つは、TelnetがTCPを介して行われ、ポート23が割り当てられることです。これは簡単なように見えるかもしれませんが、どこかで指定する必要があります。
好きなだけ送信することはできません。いくつかのものには制限と特別な意味があります。たとえば、「ネットワーク仮想端末」を定義します。これは、Telnetが確立されたときに、プリンター、白黒モニター、ANSIコードをサポートするカラーモニターなど、さまざまな端末が存在する可能性があるためです。
また、次のようなものがあります:
要約すると、WILL XXXはいずれかの当事者によって送信され、その当事者の希望(オファー)がオプションXXXの実行を開始することを示し、XXXを実行し、XXXを肯定および否定しないことを示します。同様に、DO XXXは、相手(つまり、DOの受信者)がオプションXXXを実行することを希望(要求)することを示すために送信されます。 NVTは、オプションが有効になっていないときに残されるものであるため、DO N'TおよびWO N'T応答は、両端が処理できる状態で接続を残すことが保証されています。したがって、すべてのホストは、サポートされていないオプションをまったく認識しないようにTELNETプロセスを実装し、理解できないオプション要求に拒否を返す(つまり拒否する)ことができます。
現代では、ほとんどのものはもはやそれほど重要ではありません(そして、プロトコルとしてのtelnetは、セキュリティが不足しているという理由だけでなく、もはやあまり使用されていません)。端末と実際にインターフェースする必要があります。
2つの端末を接続するときにtelnet
が「機能する」という事実自体がプロトコルの決定です。telnet
の設計者は、TCP接続の両端に「ネットワーク仮想端末」を持つモデルを使用することを決定しました、それらの仮想端末を基本的な端末機能(実際にはテレタイプ)でモデル化することにしました。
それ以上に、telnet
は単なるTCPベースのエコーサービスではありません。さまざまな目的で、インバンドで送信される制御コードをサポートします。 RFC 854 で体系化されています。
サブシステムと呼ばれる"Telnet"が提案されていますネットワークシステムプリミティブの周りのシェルプログラムで、テレタイプまたは同様の端末をサービスを提供するホストでテレタイプとして機能するリモートホスト。
これは、Wikipediaの「telnet」で言及されているRFC 15からのものです。この記事では、最初にtelnetを「アプリケーションプロトコル」と呼びます。
RFC 15は1969年9月のものです-ほんの数日前に、ちょうど50年前に最初の「インターネット」接続を確立した男との興味深いインタビューを聞きました。彼の話はそのようになりました:
"N。Armstrongとは異なり、特別なメッセージは考えていませんでした。しかし、「lo」(「login」)と入力すると、システムがクラッシュしました。「lo」(「lo and behold ")は、インターネットを介して送信される最初の2文字でした。振り返ってみると、これ以上良いものは考えられませんでした。」
(インタビューの一部を以下に示します: wiki arpanet Kleinrock )
TelnetはTCP/IPよりも古いものです。 RFC 15は「ネットワークプリミティブ」について語っています。 TCP/IPが原因で、Telnetは「休憩」であるアプリケーション層(RFC854の「交渉済みオプション」)を処理するためだけに残されました。
はい、TelnetはTCPがなくても非常に簡単です。 RFC 15は次で終わります:
TELNETサブシステムは、「レベル0」のネットワークプログラムであり、すぐに超えることができます。しかし、それは非常に単純で、かなりすぐに機能します。
本質的に2つの(異なる)システムが1つの「言語」で通信する必要があるため、「プロトコル」はtelnetで使用されます。
RFC 854でも概念が説明されています。
TELNETプロトコルは、3つの主要なアイデアに基づいて構築されています。まず、「ネットワーク仮想端末 ...」のコンセプトです。
既存の回答はすでにtelnet
がTCP変更なしで入力データをストリーミングする以上のことができることを説明しています;代わりに、「私のダムチャットクライアントプログラムはt [アプリケーション]プロトコルを作成します。 "-質問の一部です(余談ですが、実際の「TCPを介した生データ」の場合、netcat
の代わりにtelnet
を使用できます)。
プロトコルが単純である、または悪い、またはどこでも明確に指定されていないからといって、プロトコルではないという意味ではありません。 2つのシステムは、プロトコルが「TCPを介した生データ」であっても、合意されたプロトコルなしでは通信できません。一方の端でFTPを、もう一方の端でHTTPを話そうとすると、何らかの方法で問題が発生します-運が良ければ、うまくいきません。そうでない場合、あなたは間違った行動をするでしょう。 (少なくとも、HTTPサーバーと同じホスト上の非標準ポートでFTPデーモンを実行した場合、一部のブラウザーでは、XSSを実行し、被害者のブラウザーをポイントすることでCSRF保護をバイパスすることができました。 to POST FTPサーバーへのPOST $ ===これは、POSTされたコンテンツをエラーメッセージにエコーし、ブラウザはそれをHTTP/0.9応答として解釈し、JavaScriptを喜んで実行します。)
「_my dumb chat client program
_と呼んでいるプロトコルは何ですか?私のプログラムから話したいのですが」と質問するのは、完全に有効な質問です。可能な答えの1つは、「TCPを介した生データ」です。ただし、完全な答えではありません。
select()
の3番目のfdセットはエラー用であると思う人の量から判断すると、大多数の人は帯域外データが存在することさえ知らないようです-しかし、たとえそれが悪い例であったとしても、私が何をしているのか見てほしいと思います)close()
を呼び出すだけですか、それともshutdown()
を使用して、保留中のすべてのデータが最初に配信されることを確認しますか?「TCP生の入出力用のストリームソケットを開く?それはルールではありません。」と言いましたが、本当にそうですか?「TCPを使用する必要があります」、「データを-is」および「ポートXXXを使用する必要があります」というのは、ルールのようです。
(追記:私はこれを書くのに少し気を取られました;この答えの残りは少し正接です、そして「さて、すべてがプロトコルです-それは何らかの意味を持っていますか?」という自然なフォローアップの質問に答えようとします)
したがって、2つのシステムが互いに通信するたびに、既存のプロトコルを使用するか、新しいプロトコルを作成することに注意してください。手遅れになる前にプロトコルを文書化してください! (つまり、遅くとも、プロトコルが単純なものを超えた場合、または開発者だけでなく、より多くのユーザーがいる場合)。初期のP2Pプロトコルの多くは「公式クライアントのソースはドキュメントである」と言っていました。これは複雑なプロジェクトでは非常に迷惑であり、クライアントが微妙に異なるプロトコルを話し、あちこちで互換性がないことにつながります。
「あなたが生産するものに厳格で、受け入れるものに寛大」という古い格言があります-核心的な感情はいいですが、率直に言って、少なくともそれが適用されがちな方法です。保守性と互換性の問題。私は言います:詳細に指定し(隅から隅まで考えてみてください)、作成および受け入れるものを非常に厳密にしてください。そうすれば、実際のバグを防止/解決することができます。
バグを厳密に解決する例:数年前、特定のbittorrentトラッカーに問題が発生しました:一部のtorrentが一部のクライアントで機能しませんでした。クライアントは文句を言わず、異なる情報ハッシュを取得しただけなので、急流を見つけることができませんでした。彼らは何が起こっているのか理解できず、影響を受けるクライアントはバグが多いに違いないと宣言し、クライアントの使用を停止しました。 Bittorrentは非常に厳密かつ適切に指定されたベンコーディングを使用します。これには正当な理由があります。同じ入力は常にまったく同じエンコードされた出力文字列になるため、[info]ハッシュは同じ入力データに対して常に同じです。私が最初にこれらの急流の1つにぶつかったとき、私はそれを自分の-非常に厳密な-パーサーにフィードしようとしました、そしてすぐにそれは言った:Error: Bencoded dictionary keys not sorted (last='sha1', key='private')
。
どうしたの?トラッカーは、アップロードされた各torrentに「プライベート」のキーを自動的に追加し始めましたが、ベンコーディングが指定するように辞書のキーを並べ替えるのではなく、単に最後に追加しました-生成されたものに厳密ではありませんでした。一部のクライアントは、急流を部分的にのみデコードし、デコードされていない変更されていない文字列のハッシュを計算しました。一部のクライアントは、トレント全体をデコードし、ハッシュに必要な部分を再エンコードし、プロセスでキーを正しくソートし(有効なベンコーディングを作成)、別のハッシュを取得しました。私の知る限りでは、クライアントはデータが無効であると文句を言うことはありませんでした。それで、どのハッシュが正しかったですか?どちらでもない!ハッシュを計算する両方の方法は正しいですが、急流は壊れていました!クライアントの1人でも不満があった場合、バグはおそらく数か月かかるのではなく、同じ日に修正されたでしょう。 (IIRC私も数年後、まったく無関係な別のトラッカーで同じバグを報告しました。最初のソフトウェアは社内で作成されたため、同じコードベースではありませんでした)
別の例、今回はコーナーケースについて:eDonkey2000 P2Pプロトコルはed2kというカスタムハッシュを使用しました。仕様では、入力データ長がブロックサイズで正確に割り切れるというケースケースでの動作を指定していなかったため、一部のファイルに異なるハッシュを生成し、互換性のない2つの互換性のないバリアントが生まれました。 (「仕様」と言いましたが、これは初期のP2Pプロトコルだったので、仕様がなかったと確信しています。プロトコルをリバースエンジニアリングするときに、特殊なケースがおそらく見落とされていました)
詳細な仕様の必要性について:多くの場合、プロトコルのクライアントまたはファイル形式のパーサーを記述しようとすると、元のプログラマーでさえ、実際にどのようにデータがエンコードされているかわからないという状況に遭遇しました。いくつかのライブラリを使用したことがあり、実際に何が行われるかを詳細に確認したことはありません。 2つの例:
特定のAPIは、暗号化された[可変長]パケットを使用したカスタムUDPプロトコルを使用していました-ドキュメントにはAES128が指定されていましたが、使用されたパディングについては触れられていませんでした。開発者がそれについて質問されたとき、応答は次のようなものでした。
ええと、実際にはわかりません。この関数をこのJavaライブラリで使用しました。ドキュメントには、どのパディングが使用されているかが記載されていないようです。
特定のデバイスのWebサイトには、savefileとのインターフェースについて次のように書かれています。
保存された* .logicdataファイルを作成または変更することはできません。これは、ファイルがboostバイナリシリアル化で生成され、非常に複雑なオブジェクト構造が含まれているためです。実際には、それがどのように機能するかさえ理解していません。 Boostシリアライゼーションは非常に複雑です。
(注:ただし、実際には、データをエクスポートできるようにするのに十分なファイル形式のリバースエンジニアリングを行うのにそれほど長くはかかりません)
いくつかの例は、エンコーディング、ファイル形式、またはカスタムアルゴリズムに関するものでした(ただし、最後のプロトコルを除いて、依然としてプロトコル内で使用されています)が、これはすべてすべてに当てはまると思います。プロトコル、ファイル形式、エンコーディング、カスタムアルゴリズムのいずれであっても、
Telnetプロトコルは非常に単純なプロトコルですが、存在しています。 「存在する」とは、Telnetクライアントが受信したすべてのバイトを、それを読み取るプログラム(通常はシェル)に送信しないことを意味します。
プロトコルは
バイト
0xff
(255)は、次のバイトがTelnetコマンドであることを意味します。 0xffを送信する場合は、2倍(0xff, 0xff
)して、コマンドを送信するつもりがないことをtelnetに通知する必要があります。
つまり、プロトコルは非常に単純で、ほとんど取るに足らないものです。しかし、これは単純なtcpパススルーではありません。
(反対側のソフトウェア/サーバーの代わりに)Telnetに送信できるコマンドに興味がある場合は、RFCを参照してください: https://tools.ietf.org/html/rfc854 。基本的にtelnetは以下を定義します:
NAME CODE MEANING
SE 240 (0xf0) End of subnegotiation parameters.
NOP 241 (0xf1) No operation.
Data Mark 242 (0xf2) The data stream portion of a Synch.
This should always be accompanied
by a TCP Urgent notification.
Break 243 (0xf3) NVT character BRK.
Interrupt Process 244 (0xf4) The function IP.
Abort output 245 (0xf5) The function AO.
Are You There 246 (0xf6) The function AYT.
Erase character 247 (0xf7) The function EC.
Erase Line 248 (0xf8) The function EL.
Go ahead 249 (0xf9) The GA signal.
SB 250 (0xfa) Indicates that what follows is
subnegotiation of the indicated
option.
WILL (option code) 251 (0xfb) Indicates the desire to begin
performing, or confirmation that
you are now performing, the
indicated option.
WON'T (option code) 252 (0xfc) Indicates the refusal to perform,
or continue performing, the
indicated option.
DO (option code) 253 (0xfd) Indicates the request that the
other party perform, or
confirmation that you are expecting
the other party to perform, the
indicated option.
DON'T (option code) 254 (0xfe) Indicates the demand that the
other party stop performing,
or confirmation that you are no
longer expecting the other party
to perform, the indicated option.
IAC 255 (0xff) Data Byte 255.
上記のコマンドは具体的にはTelnetコマンドであることに注意してください。これらは、クライアントまたはサーバー側のターミナルプロトコルの一部ではありません。たとえば、UNIXでプロセスを終了する場合は、通常ctrl-c
と入力します。これは通常、ターミナルから0x03
としてシェルに送信され、シェルはSIGINT
をシェルが実行しているプロセスに送信します。しかし、telnet自体は0xff, 0xf4
を定義して、SIGINT
をtelnet固有のプロトコルであるプロセスに送信します。同様に、端末は通常、現在の行をクリアするために0x1b, 0x4b
を送信しますが、telnetは0xff, 0xf8
を定義します。