「Linux ネットワークプログラミング-01-01」 ソケットプログラミング (1) ソケットプログラミングの基礎

目次

 

1. 予備知識 

1.IPアドレス

2. ポート番号

3. ネットワーク通信

4. TCPプロトコルの概要

5. UDP プロトコルの概要

6. ネットワークバイトオーダー


2、ソケット

1.ソケット(ソケット)とは何ですか?

2. なぜソケットが必要なのでしょうか?

3. ソケットの主な種類

4. ソケットのドメインとアドレス ファミリ

拡張] ネットワークソケット


3.ソケットAPI

1. ソケット API とは何ですか?  

2. ソケット API があるのはなぜですか?

3. ソケットプログラミング共通API

3.1 ソケット()

3.2 バインド()

3.3 聞く()

3.4 accept()

3.5 接続 ()


4、sockaddr

1. それは何ですか?

2. なぜですか?

3. sockaddr の分類

4. Linuxにおけるsockaddrの宣言

4.1struct sockaddr (ヘッダファイル内:in)

 4.2 struct sockaddr_in (ヘッダファイル内: in)

 4.3 struct sockaddr_un (ヘッダファイル内: in)

5. struct sockaddr_in を作成して入力します。

6. sockaddr を使用してパラメータを渡す


1. 予備知識 

1.IPアドレス_

1.1 それは何ですか?

        IP アドレスは、 IP プロトコルでネットワーク内のさまざまなホストを識別するために使用されるアドレスです。


1.2 IPv4 と IPv6

  • IPv4 の場合、IP アドレスは 4 バイト、32 ビットの整数です。通常、IPv4 アドレスを表すには、123.145.67.89 などの「ドット付き 10 進数」文字列を使用します。ドットで区切られた各数値はバイトを表し、範囲は 0 ~ 255 です。
  • IPv6 の場合、IP アドレスの長さは 16 バイト 128 ビットで、IPv4 アドレスの長さの 4 倍です。したがって、IPv4 のドット 10 進形式は適用できなくなり、16 進表記が使用されます。具体的な表現方法については、 IPv6-Baidu百科事典をご覧ください。

1.3 送信元IPと宛先IP

  • IP データグラム (ネットワーク層がデータリンク層にデータを送信するときにカプセル化される) のヘッダーには、それぞれ送信元 IP アドレスと宛先 IP アドレスと呼ばれる 2 つの IP アドレスがあります。
  • 送信元 IP アドレス: メッセージを送信するホストのアドレス。
  • 宛先 IP アドレス: メッセージを受信するホストのアドレス。

2. ポート番号

2.1 それは何ですか?

         ポート番号は、プロセスを識別するために使用される 2 バイト 16 ビットの整数です。

2.2  pid は唯一のプロセスを表しポート番号も唯一のプロセスを表しますでは、この 2 つの関係は何でしょうか?

        
  • 「ポート番号」は「プロセスpid」とは関係ありません。
    ポート番号はネットワーク通信に使用され、プロセス PID はプロセス管理に使用されますが、ネットワーク通信とプロセス管理は無関係なモジュールです。ポート番号の置換に pid を使用しない機能は、機能を分離し、システムの結合度を下げるためです。
  • すべてのプロセスにポート番号が必要なわけではありませんが、すべてのプロセスに PID が必要です。
  • プロセスには複数のポート番号を持つことができますが、 1 つのポート番号を占有できるのは 1 つのプロセスのみです。

2.3 送信元ポート番号と宛先ポート番号について

  • トランスポート層プロトコル (TCPおよびUDP)のデータ セグメントには 2 つのポート番号があり、それぞれ送信元ポート番号と宛先ポート番号と呼ばれます。 誰がデータを送信し誰に送信するか」を記述します。
  • 送信元ポート番号: メッセージを送信したプロセスのポート番号。
  • 宛先ポート番号: メッセージを受信するプロセスのポート番号。

3. ネットワーク通信

3.1 それは何ですか?

        ネットワーク通信の本質はプロセス間通信です。


3.2 なぜ?

        データを送信するホストはプロセスによってデータを送信し、データを受信するホストもプロセスに依存してデータを処理します。単純化後、1 つのプロセスがデータを送信し、別のプロセスがデータを処理します。したがって、ネットワーク通信の本質はプロセス間通信です。


3.3 ネットワーク通信中に IP アドレスとポート番号で指定されたプロセスを確実に見つけるにはどうすればよいですか?

  • クライアントプロセスはサーバプロセスに情報を送信しますが、
            通常、サーバプロセスは終了を避けるために起動されるため、サーバプロセスのポート番号が勝手に変更されることはありません。したがって、クライアントプロセスは、ソフトウェアのダウンロード時に取得したIPアドレス+ポート番号に基づいてサーバープロセスを見つけることができます。     
  • サーバー プロセスはクライアント プロセスに情報を送信します。
            ユーザーがソフトウェアを開いた後、クライアント プロセスとポート番号が作成されます。このとき、クライアント プロセスはデータを取得するために最初にサーバーに情報を送信する必要があるため、サーバー プロセスはクライアント プロセスを取得します。IP アドレス + ポート番号、サーバー プロセスは、クライアント プロセスの IP アドレス + ポート番号に従ってクライアント プロセスを見つけることができます。(つまり、ソフトウェアを開いた後、通常はしばらくロードされます)

3.4 OS はポート番号に基づいて指定されたプロセスをどのように見つけますか?

        最下位層はハッシュ方式を使用してポート番号とプロセス PID または PCB の間のマッピング関係を確立し、最下位層がポート番号を取得すると、ポート番号に従ってハッシュ テーブル内で対応するプロセスを見つけることができます。


3.5 ネットワーク通信は双方向で行われます

        ホストが別のホストにデータを送信する場合、送信者はデータを送信するだけでなく、自身の IP アドレスとポート番号も受信者に送信するため、受信者は送信者にデータを返すことができます。したがって、コミュニケーションは双方向です。


4. TCPプロトコルの概要

  • TCP (Transmission Control Protocol伝送制御プロトコル)は、TCP プロトコルは、接続、信頼性の高い、バイト ストリーム指向のトランスポート層通信プロトコルです。
  • TCP プロトコルはコネクション指向であり、2 つのホスト間でデータ送信を行う場合は、まず接続を確立する必要があり、接続が正常に確立されて初めてデータ送信を実行できます。
  • TCP プロトコルはパケット損失率に注意を払い、データ送信中のパケット損失や順序異常の問題を解決するために大量のオーバーヘッドを費やして、パケットが失われないようにするため、TCP プロトコルは信頼できます。損失。ファイル転送、電子メール、Web サイトへのアクセスには通常、TCP プロトコルが使用されます。

5. UDP プロトコルの概要

  • UDP (User Datagram Protocol ユーザー データグラムプロトコル)、UDP プロトコルは、コネクションレスで信頼性の低い、データグラム指向のトランスポート層通信プロトコルです。
  • 通信に UDP プロトコルを使用する場合、接続を確立する必要はなく、2 つのホスト間でデータ送信が必要な場合は、データをピア ホストに直接送信できます。
  • UDP プロトコルは効率を重視しており、データ送信中に低い確率で発生するパケット損失や順序の乱れには対応していないため、信頼性が低くなります。ライブ ストリーミングでは通常、UDP プロトコルが使用されます。

6. ネットワークバイトオーダー

6.0 ビッグエンディアンとリトルエンディアン

  • ビッグエンディアン: データの下位バイトを上位アドレスに配置し、上位バイトを下位アドレスに配置します。
    (ビッグエンディアン下位アドレス上位バイト:「ビッグブラザー上位」)
  • リトルエンディアンのバイトオーダーでは、データの下位バイトを下位アドレスに配置し、上位バイトを上位アドレスに配置します。
    (リトルエンディアン下位アドレス下位バイト:「リトルブラザー」)

6.1 それは何ですか?

        
         つまり、ネットワーク通信で一般的に観察されるバイト オーダーは、 ビッグ エンディアン バイト オーダー (下位バイト、上位アドレス) として定義されます。

6.2 なぜ?

        コンピュータごとに バイトオーダー が異なるため、ネットワーク通信時に指定がない場合、送信側はビッグエンディアンモードでデータを送信し、受信側はリトルエンディアンモードでデータを読み取ります。

6.3 どのように定義するか?

        TCP/IP プロトコルは、ネットワーク データ フローがビッグ エンディアンのバイト順、つまり下位アドレスと上位バイトを採用することを規定しています。 ホストがビッグエンディアンであるかリトルエンディアンであるかに関係なく、この TCP/IP で指定されたネットワーク バイト オーダーに従ってデータを送受信します。
現在の送信ホストがリトル エンディアンの場合は、データを送信する前にデータをビッグ エンディアンに変換する必要があります。それ以外の場合は、直接送信します。

6.4 ネットワークバイトオーダーとホストバイトオーダー間の変換関数

        ネットワーク プログラムを移植可能にして、ビッグ エンディアンとリトル エンディアンのコンピューターでコンパイルした後に同じCコードを正常に実行できるようにするために次のライブラリ関数を呼び出してネットワーク バイト オーダーとホスト バイト オーダーを変換できます。

#include <arpa/inet.h>
 
uint32_t htonl(uint32_t hostlong);
//将主机字节序(h)转换为(to)网络字节序(n)要转化的数据是长整数(l)。

uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
  • これらの関数名は覚えやすいです。hホスト、nネットワーク、l32ビット長整数、s は16ビット短整数を意味しますしたがって、htonl は、ホストのバイト オーダー (h) をネットワークのバイト オーダー (n) に変換し、変換されるデータは長整数 (l) であることを意味します。
  • ホストがリトルエンディアンの場合、これらの関数はそれに応じて引数を変換し、 を返します
  • ホストがビッグエンディアンの場合、これらの関数は変換を行わず引数を変更せずに返します。 

2、ソケット

1.ソケット(ソケット)とは何ですか

        IP アドレス + ポート番号はソケット (ソケット) であり 、特定のホスト上の特定のプロセスを識別するために使用されます。

2. なぜソケットが必要なのでしょうか?

        ソケットを使用すると、異なるホストのプロセスがネットワーク内で相互に認識し、ネットワーク上で通信できるようになります (プロセス間通信の前提条件は相互に認識できることです)。そのため、ソケットはネットワーク通信の基礎となります。次に、ソケットを使用すると、開発者は汎用ネットワーク通信インターフェイスを開発でき、ユーザーもこれらのインターフェイスをソケットで使用できます。

3. ソケットの主な種類

  • ストリームソケット(SOCK_STREAM) : TCP プロトコルのデータを読み取るために使用されます。
  • データグラムソケット(SOCK_DGRAM) : UDP プロトコルのデータを読み取るために使用されます。
  • Raw ソケット(SOCK_RAW) : アプリケーション層からトランスポート層を直接バイパスして、基礎となるプロトコルに直接アクセスできるため、Raw ソケットはカーネルによって処理されない IP パケットの読み取りと書き込みが可能ですが、ストリーム ソケットは TCP データの読み取りのみが可能です。プロトコルの違いにより、データグラム ソケットは UDP プロトコルのデータのみを読み取ることができます。したがって、他のプロトコルによって送信されたデータにアクセスしたい場合は、生のソケットを使用する必要があります。

        ソケットの種類から、ネットワーク通信が準拠しているトランスポート層プロトコル (TCP、UDP など) がわかります。

4. ソケットのドメインとアドレス ファミリ

ソケットを使用して通信するには、次の 2 つの前提条件があります。 1. ソケットのタイプが同じである 2. ソケットが同じドメイン内にある

4.1 ソケットドメインとは何ですか?

        ドメインはソケットの作業範囲です。ソケット通信で使用するネットワークメディアを指定するために使用されます。


4.2 共通ソケットフィールド

        AF_INET / PF_INET ------------- ソケットが IPv4 としてのインターネット アドレス タイプで動作することを示します。

        AF_INET6 / PF_INET6 ------------- ソケットが IPv6 としてのインターネット アドレス タイプで動作することを示します。

        AF_UNIX / AF_LOCAL ------------- ソケットが Unix システムで動作することを示します。

        プレフィックス AF_ はアドレス ファミリ (アドレス ファミリ) を示し、PF_ はプロトコル ファミリ (プロトコル ファミリ) を示します。


4.3 アドレスファミリーとは何ですか?

        同じタイプのソケット アドレスのコレクション。ソケット アドレスのタイプを表すために使用されます。

        たとえば、 AF_INET は、それが IPv4 アドレス ファミリであることを示します。これは、ソケットアドレス タイプが IPv4 であることを意味します。

拡張] ネットワークソケット

  1. ストリーム ソケット (SOCK_STREAM)ストリーム ソケットは、コネクション型で信頼性の高いデータ送信サービスを提供するために使用されます。このサービスは、データがエラーや重複なく送信され、順番に受信されることを保証します。ストリーム ソケットが信頼性の高いデータ サービスを実現できるのは、TCP プロトコルのおかげです。ストリーム ソケットは TCP プロトコル データの読み取りのみが可能です
  2. データグラム ソケット (SOCK_DGRAM)データグラム ソケットは、コネクションレス型サービスを提供します。本サービスは、データ通信の信頼性を保証するものではなく、通信中にデータの消失や重複が発生する可能性があり、データが順番に受信されることを保証するものではありません。データグラム ソケットは、データ送信に UDP (ユーザー データグラム プロトコル) プロトコルを使用します。データグラムソケットはデータ伝送の信頼性を保証できないため、プログラム側でデータ損失の可能性を考慮する必要があります。データグラム ソケットは UDP プロトコル データのみを読み取ることができます。

拡張】強力ソケット

        ソケットは非常に強力です。この記事ではネットワーク通信用のソケットのみを紹介していますが、ソケットはローカル通信、さまざまな種類のネットワーク通信など、ほぼすべての種類のプロセス間通信に使用できます。


3.ソケットAPI

1. ソケット API とは何ですか?  

ネットワーク開発のためにプログラマ(アプリケーション層)        に提供されるインターフェースであり、異なるホスト上のプロセス間の通信を実現するために使用されます。

        ソケットAPI (ソケットプログラミング インターフェイス)は、実際には、異なるホストのプロセス間の通信を実現するために、トランスポート層によってアプリケーション層に 提供されるプログラミング インターフェイスです。トランスポート層は、ネットワークに基づいてプロセス間の論理チャネルを提供します。 、およびアプリケーション層のプロセスはトランスポート層を使用して、別のホストのプロセスと通信します。ソケットはアプリケーション層とトランスポート層の間のブリッジであり、ソケット プログラミングを使用してクライアント アプリケーションとサーバー アプリケーションを開発し、ネットワークを介したグローバル通信を実現できます。


2. ソケット API があるのはなぜですか?

        ソケット(ソケット)はネットワーク通信の前提にすぎず、共通のネットワークインターフェースを開発するだけで異なるホスト間のプロセスの通信を実現できます。Linux におけるこのインターフェイスのセットは、ソケット API (ソケット プログラミング インターフェイス) です。


3. ソケットプログラミング共通API

3.1 ソケット()

// TCP/UDPネットワークプログラムでクライアント+ サーバー用のsocket_fd(ソケットファイル記述子)を作成

3.2 バインド()

// socket_fd と sockaddr_in を TCP/UDPネットワーク プログラム サーバー バインドします。

3.3 聞く( )

// TCP ネットワーク プログラムで サーバーのソケットのリッスンを開始します

3.4 受け入れる( )

// TCP ネットワークプログラムで サーバーへのリクエストを受信します

3.5 接続( )

// TCP ネットワークプログラムで サーバーへの接続を確立します

4、sockaddr

1. それは何ですか?

        struct sockaddr (ソケット アドレス構造) は、ソケットとソケット アドレス タイプ (アドレス ファミリ)を保存するために Linux で使用される構造です。


2. なぜですか?

        Socket API を使用するには、ソケットを渡す必要があります。Linux は、ソケットとソケット アドレス タイプ (アドレス ファミリ)を保存するために struct sockaddr を使用することを選択します。Linux でソケット API を使用するには、struct sockaddr* を渡す必要があります。


3.  sockaddr の分類

        Linux にはソケット API (ソケット プログラミング インターフェイス)セットが 1つしかありませんが、さまざまな種類のソケット (IPv4 用、IPv6 用、ローカル通信用のソケット) があるため、struct sockaddr 、 struct sockaddr_in 、 struct   sockaddr_unを使用して異なるものを区別します。ソケットの種類:


sockaddr、sockaddr_in、および sockaddr_un 構造ヘッダーの 16 ビット (2 バイト) は同じです。これらの 16 ビットは、ソケットのアドレス タイプ (アドレス ファミリ)に従って、ソケットのアドレス タイプ (アドレス ファミリ)を区別するために使用されます。 それぞれ定数 AF_INET、AF_INET6... として定義されます。


Socket API は struct sockaddr * 型を使用してパラメータを渡します。sockaddr_in または sockaddr_un から sockaddr への型変換は、Socket API によって認識されます。渡されたパラメータ sockaddr は、最初の 2 バイトでネットワーク通信かローカル通信かを判定し、結果がわかった後、強制的に型を sockaddr_in 構造体と sockaddr_un 構造体に戻します。この利点はプログラムの汎用性であり、IPv4、IPv6、UNIX ドメイン ソケットなどのさまざまなアドレス タイプ (アドレス ファミリ) の sockaddr 構造体ポインタをパラメータとして受け取ることができます。


4. Linuxにおけるsockaddrの宣言

4.1 struct   sockaddr (ヘッダー ファイル内: <sys/socket.h> )


 4.2 struct  sockaddr_in (ヘッダー ファイル: <netinet/in.h> 内)


 4.3 struct  sockaddr_un (ヘッダー ファイル: <sys/un.h> 内)


5. struct  sockaddr_inを作成して入力します。

4.0 は、構造体宣言が配置されているヘッダー ファイルをインポートします。

#include <netinet/in.h>

ヘッダー ファイル<netinet/in.h>で宣言されたstruct  sockaddr_in


4.1 struct sockaddr_in 変数を定義します。

struct sockaddr_in local;
  • struct sockaddr_in: ネットワーク通信用の Ipv4 および Ipv6 のソケット構造を定義するために使用されます。
  • struct sockaddr_un: UNIX_Domain_Socket (Unix ドメイン ソケット: 同一ホスト上のプロセス間通信に使用) を定義するために使用されます。ローカルコミュニケーション用に。

4.2 構造体の初期化

bzero(&local, sizeof(local)); 

bzero() または memset() を使用して、構造体のメモリ空間を 0 に初期化します。


4.3 ソケット アドレス タイプ (つまり、アドレス ファミリ) を設定します。

local.sin_family = AF_INET;


4.4 ポート番号を設定します (ポート番号を保存する変数は port で、2 バイトの 16 ビット整数です)

local.sin_port = htons(port);

ポート番号は相手が取得する必要があり、またネットワークデータの一部であるため、ビッグエンディアンとスモールエンディアンの問題を考慮する必要があり、htons 関数を使用してホストのバイトオーダーをネットワークのバイトオーダーに変換します。


4.5 IP アドレスを設定します (IP アドレスを保存する変数は ip、ドット付き 10 進数文字列です)

local.sin_addr.s_addr = inet_addr(ip);

 inet_addr() の役割:

        1. ドット付き 10 進文字列形式の IP アドレス -> 4 バイト整数

        2. IP アドレスは、大小の端も考慮する必要があります: 4 バイト整数 -> ネットワーク シーケンス


6. sockaddr を使用してパラメータを渡す

        Socket API は struct sockaddr * 型パラメータのみを受け入れるため、Socket API で認識されるように sockaddr_in および sockaddr_un を sockaddr に変換する必要があります。
        渡されたパラメータ sockaddr は、最初の 2 バイトでネットワーク通信かローカル通信かを判定し、結果がわかった後、強制的に型を sockaddr_in 構造体と sockaddr_un 構造体に戻します。この利点は、IPv4、IPv6、および UNIX ドメイン ソケットのさまざまな種類の sockaddr 構造体ポインタをパラメータとして受け取ることができるプログラムの汎用性です。

おすすめ

転載: blog.csdn.net/look_outs/article/details/132167770