インターネット
 Computer >> コンピューター >  >> ネットワーキング >> インターネット

インターネットはどのように話すか

コミュニケーションの物語

インターネットが実際にどのように話すのか疑問に思ったことはありませんか?あるコンピューターは、インターネットを介して別のコンピューターとどのように「会話」しますか?

人々が互いにコミュニケーションをとるとき、一見意味のある文章にまとめられた単語を使用します。これらの文の意味について合意したからこそ、これらの文は意味を成します。いわば、通信のプロトコルを定義しました。

結局のところ、コンピューターはインターネットを介して同様の方法で互いに通信します。しかし、私たちは先を行っています。人は口を使ってコミュニケーションをとります。まず、コンピューターの口が何であるかを理解しましょう。

ソケットに入る

ソケットは、コンピューター サイエンスの最も基本的な概念の 1 つです。ソケットを使用して、相互接続されたデバイスのネットワーク全体を構築できます。

コンピュータ サイエンスの他のすべてのものと同様に、ソケットは非常に抽象的な概念です。したがって、ソケットとは何かを定義するよりも、ソケットの機能を定義する方がはるかに簡単です。

それで、ソケットは何をしますか? 2 台のコンピューターが相互に通信するのに役立ちます。これはどのように行うのですか? send() と呼ばれる 2 つのメソッドが定義されています。 と recv() それぞれ送信と受信用。

さて、それはすべて素晴らしいですが、send() は何をしますか と recv() 実際に送受信?人は口を動かすと言葉を交わします。ソケットがメソッドを使用するとき、ビットとバイトを交換します。

例を挙げて方法を説明しましょう。 A と B の 2 台のコンピューターがあるとします。コンピューター A はコンピューター B に何かを伝えようとしています。したがって、コンピューター B はコンピューター A の言葉を聞こうとしています。

インターネットはどのように話すか
バッファ付きソケット

バッファの読み取り

少し奇妙に見えますよね? 1 つは、両方のコンピュータが「バッファ」というタイトルの中央のバーを指しているということです。

バッファとは何ですか?バッファはメモリ スタックです。各コンピューターのデータが保存される場所であり、カーネルによって割り当てられます。

次に、なぜ両方が同じバッファーを指しているのでしょうか?まあ、それは実際にはあまり正確ではありません。各コンピューターには、独自のカーネルによって割り当てられた独自のバッファーがあり、ネットワークは 2 つの個別のバッファー間でデータを転送します。ただし、ここではネットワークの詳細には触れたくないので、両方のコンピューターが「間の空白のどこかに」配置された同じバッファーにアクセスできると仮定します。

さて、これが視覚的にどのように見えるかがわかったので、それをコードに抽象化しましょう.

#Computer A sends data computerA.send(data) 
#Computer B receives data computerB.recv(1024)

このコード スニペットは、上の画像が表すものとまったく同じことを行います。 1 つの好奇心を除いて、computerB.recv(data) とは言いません .代わりに、データの代わりに一見乱数を指定します。

理由は簡単です。ネットワーク上のデータはビット単位で送信されます。したがって、コンピュータ B で受信するときは、ビット の数を指定します。 いつでも喜んで受け取ります。

一度に受信するために 1024 バイトを選択したのはなぜですか?特に理由はありません。通常は、受け取るバイト数を 2 の累乗で指定するのが最善です。私は 1024 を選びました。これは 2¹⁰ です。

では、バッファはこれをどのように把握するのでしょうか?コンピューター A は、保存されているデータをバッファーに書き込み、または送信します。コンピューター B は、そのバッファーに格納されているものの最初の 1024 バイトを読み取るか受信することを決定します。

よし、すごい!しかし、これら 2 台のコンピューターはどのようにして互いに通信することを知っているのでしょうか?たとえば、コンピューター A がこのバッファーに書き込みを行うとき、コンピューター B がそれを取得しようとしていることがどのようにわかりますか?言い換えると、2 台のコンピューター間の接続に固有のバッファーがあることをどのように保証できるのでしょうか?

IP への移植

インターネットはどのように話すか
コンピューターのポートと IP

上の画像は、私たちがずっと取り組んできた同じ 2 台のコンピューターと、もう 1 つの詳細が追加されたものを示しています。各コンピューターの前に、バーの長さに沿って多数の数字がリストされています。

各コンピューターの前にある長いバーは​​、特定のコンピューターをインターネットに接続するルーターであると考えてください。各バーに表示されている番号はポートと呼ばれます .お使いのコンピュータには現在、何千ものポートが利用可能です。各ポートはソケット接続を許可します。上の画像では 6 つのポートしか示していませんが、おわかりいただけたでしょうか。

255 未満のポートは、通常、システム コールと低レベル接続用に予約されています。一般に、8000 などの上位 4 桁のポートで接続を開くことをお勧めします。上の画像ではバッファを描画していませんが、各ポートには独自のバッファがあると想定できます。

バー自体にも番号が関連付けられています。この番号を IP アドレスと呼びます。 IP アドレスには、それに関連付けられた一連のポートがあります。次のように考えてください:

                          127.0.0.1                             / | \                            /  |  \                           /   |   \                        8000  8001 8002

よし、コンピューター A とコンピューター B の間の特定のポートで接続をセットアップしましょう。

# computerA.pyimport socket 
computerA = socket.socket() 
# Connecting to localhost:8000 computerA.connect(('127.0.0.1', 8000)) string = 'abcd' encoded_string = string.encode('utf-8') computerA.send(encoded_string)

computerB.py のコードは次のとおりです。

# computerB.py import socket 
computerB = socket.socket() 
# Listening on localhost:8000 computerB.bind(('127.0.0.1', 8000)) computerB.listen(1) 
client_socket, address = computerB.accept() data = client_socket.recv(2048) print(data.decode('utf-8'))

コードに関しては少し先を行っているように見えますが、順を追って説明します。 A と B の 2 台のコンピューターがあることがわかっています。したがって、データを送信するために 1 台、データを受信するために 1 台が必要です。

データを送信するために A を、データを受信するために B を任意に選択しました。この行で computerA.connect((‘127.0.0.1’, 8000) 、computerA を IP アドレス 127.0.0.1 のポート 8000 に接続させています。

注:127.0.0.1 は通常、マシンを参照する localhost を意味します

次に、コンピューター B については、IP アドレス 127.0.0.1 のポート 8000 にバインドします。さて、なぜ私が 2 台の異なるコンピューターに同じ IP アドレスを使用しているのか不思議に思われるでしょう。

それは私が浮気をしているからです。ここでは、1 台のコンピューターを使用して、ソケットの使用方法を説明しています (簡単にするために、基本的には同じコンピューターとの間で接続しています)。通常、2 台の異なるコンピューターは 2 つの異なる IP アドレスを持っています。

データ パケットの一部として送信できるのはビットのみであることは既にわかっているため、送信する前に文字列をエンコードします。同様に、コンピューター B で文字列をデコードします。上記の 2 つのファイルをローカルで実行する場合は、必ず computerB.py を実行してください。 最初にファイルします。 computerA.py を実行すると 最初にファイルを作成すると、接続拒否エラーが発生します。

クライアントへのサービス

インターネットはどのように話すか
クライアントとサーバー間のデータ送信

これまで説明してきたことが非常に単純化されたクライアント/サーバー モデルであることは、多くの人にとってかなり明白であると確信しています。実際、上の画像からわかるように、コンピューター A をクライアントに、コンピューター B をサーバーに置き換えただけです。

クライアントとサーバーの間で行われる絶え間ない通信の流れがあります。前のコード例では、データ転送のワン ショットについて説明しました。代わりに、クライアントからサーバーに送信される一定のデータ ストリームが必要です。ただし、そのデータ転送がいつ完了するかを知りたいので、リッスンを停止できることもわかっています。

アナロジーを使ってこれをさらに調べてみましょう。次の 2 人の会話を想像してみてください。

インターネットはどのように話すか

2人が自己紹介をしようとしています。ただし、同時に話そうとはしません。 Rajが最初に行くとしましょう。ジョンは、ラジが自己紹介を始める前に、自己紹介を終えるまで待ちます。これはいくつかの学習したヒューリスティックに基づいていますが、一般的に上記をプロトコルとして説明できます。

クライアントとサーバーには同様のプロトコルが必要です。あるいは、データのパケットを送信する番になったとき、どうすればわかりますか?

これを説明するために簡単なことをします。たまたま文字列の配列であるデータを送信したいとしましょう。配列が次のようになっているとしましょう:

arr = ['random', 'strings', 'that', 'need', 'to', 'be', 'transferred', 'across', 'the', 'network', 'using', 'sockets']

上記は、クライアントからサーバーに書き込まれるデータです。別の制約を作成しましょう。サーバーは、その時点で送信される文字列が占めるデータとまったく同じデータを受け入れる必要があります。

したがって、たとえば、クライアントが文字列「random」を介して送信する場合、各文字が 1 バイトを占めると仮定すると、文字列自体は 6 バイトを占めます。 6 バイトは、6*8 =48 ビットに等しくなります。したがって、文字列「random」がソケットを介してクライアントからサーバーに転送されるためには、サーバーは特定のデータ パケットの 48 ビットにアクセスする必要があることを認識している必要があります。

これは、問題を分解する良い機会です。最初に把握しなければならないことがいくつかあります。

文字列が占めるバイト数をどのように計算するのですかパイソン?

まず、文字列の長さを計算することから始めることができます。それは簡単です。len() を呼び出すだけです。 .ただし、文字列の長さだけでなく、文字列が占めるバイト数を知る必要もあります。

最初に文字列をバイナリに変換してから、結果のバイナリ表現の長さを見つけます。これで、使用されたバイト数がわかります。

len(‘random’.encode(‘utf-8’)) 私たちが望むものを与えてくれるでしょう

それぞれが占有するバイト数を送信する方法文字列をサーバーに送信しますか?

簡単です。バイト数 (整数) をその数値のバイナリ表現に変換し、サーバーに送信します。これで、サーバーは文字列自体を受け取る前に文字列の長さを受け取ることが期待できます。

クライアントがすべての文字列?

会話の類推から、データ転送が完了したかどうかを知る方法が必要であることを思い出してください。コンピューターには、信頼できる独自のヒューリスティックがありません。そこで、ランダムなルールを提供します。文字列「end」を介して送信すると、サーバーがすべての文字列を受信し、接続を閉じることができることを意味します。もちろん、これは配列の最後の部分を除いて、文字列「end」を使用できないことを意味します。

これまでに設計したプロトコルは次のとおりです。

インターネットはどのように話すか
私たちの単純なプロトコル

文字列の長さは 2 バイトで、その後に可変長の実際の文字列が続きます。これは、前のパケットで送信された文字列の長さに依存し、文字列の長さと文字列自体の送信を交互に行います。 EOT は End Of Transmission の略で、文字列「end」を送信すると、送信するデータがもうないことを意味します。

注:先に進む前に、指摘しておきたいことがあります。これは非常に単純でばかげたプロトコルです。適切に設計されたプロトコルがどのようなものかを知りたい場合は、HTTP プロトコル以外を探す必要はありません。

これをコード化しましょう。以下のコードにはコメントが含まれているので、一目瞭然です。

クライアントが実行されています。次に、サーバーが必要です。

上記の要点の特定のコード行をいくつか説明したいと思います。最初は clientSocket.py から ファイル。

len_in_bytes = (len_of_string).to_bytes(2, byteorder='little')

上記が行うことは、数値をバイトに変換することです。 to_bytes 関数に渡される最初のパラメーターは、len_of_string を変換した結果に割り当てられるバイト数です。 そのバイナリ表現に。

2 番目のパラメーターは、リトル エンディアン形式とビッグ エンディアン形式のどちらに従うかを決定するために使用されます。詳細については、こちらをご覧ください。現時点では、そのパラメーターについては常にほとんど使用しないことに注意してください。

次に確認したいコード行は次のとおりです。

client_socket.send(string.encode(‘utf-8’))

‘utf-8’ を使用して文字列をバイナリ形式に変換しています エンコーディング。

次に、serverSocket.py で ファイル:

data = client_socket.recv(2) str_length = int.from_bytes(data, byteorder='little')

上記のコードの最初の行は、クライアントから 2 バイトのデータを受け取ります。 clientSocket.py で文字列の長さをバイナリ形式に変換したときのことを思い出してください。 、結果を 2 バイトで格納することにしました。これが、同じデータに対してここで 2 バイトを読み取る理由です。

次の行では、バイナリ形式を整数に変換します。 byteorder byteorder に合わせて「little」 クライアントで使用しました。

先に進んで 2 つのソケットを実行すると、クライアントが送信する文字列がサーバーによって出力されることがわかります。通信を確立しました!

結論

さて、これまでかなりのことをカバーしてきました。つまり、ソケットとは何か、それらをどのように使用するか、非常に単純で愚かなプロトコルを設計する方法です。ソケットの仕組みについて詳しく知りたい場合は、Beej の Guide To Network Programming を読むことを強くお勧めします。その電子書籍にはすばらしいものがたくさんあります。

もちろん、これまでにこの記事で読んだ内容を、RaspberryPi カメラからコンピューターへの画像のストリーミングなど、より複雑な問題に適用することもできます。楽しんでください!

必要に応じて、Twitter または GitHub で私をフォローしてください。私のブログはこちらからもご覧いただけます。いつでもご連絡ください!

2019 年 2 月 14 日に https://redixhumayun.github.io/networking/2019/02/14/how-the-internet-speaks.html で最初に公開されたもの


  1. インターネットでのアップロード速度を上げる 7 つの方法

    オフィスで仕事をしていても、自宅で仕事をしていても、共有相手がファイルやビデオにできるだけ早くアクセスできるように、インターネットのアップロード速度を向上させる必要があります。アップロード速度が遅い場合アップロード速度を上げる方法を知りたいので、作業を早期に終了して他の楽しみを楽しみ始めることができます。そこで、メールやクラウドでのアップロード速度を上げるためのヒントと方法を紹介します。 速度テストを実行して、Wi-Fi 接続が正常に機能しているかどうかを確認してください。テストして確認したら、アップロード速度を上げるためのヒントを試してください。 アップロード速度を上げる方法 1.ルーター

  2. インターネットから個人情報を削除する方法

    サイバー攻撃やハッキングが世界中で起こっているため、一部の人々はインターネットをやめて、古き良き時代の生活を送っています。しかし、真剣に考えれば、オンラインでないと多くのことを見逃してしまうため、これは実行可能な解決策とは思えません。別の方法は、インターネットの使用を減らし、可能な限り安全な方法で使用することです。ただし、過去のオンライン アクティビティはインターネット上に残るため、そのデータを保護する必要があります。このブログでは、インターネットから個人情報を削除し、個人データ保護の手順に従う方法について説明します。 インターネットから自分自身を完全に削除することはできないかもしれませんが