Linux ネットワークプログラミング機能の簡単な分析

Linux ネットワークプログラミング機能の簡単な分析

ネットワーク プログラミングの基本的な機能: これは、TCP プロトコル通信を実現するための基本的なステップでもあります。実装コードは最後にあります。通信するには、IP を独自の IP に変更する必要があります。

1.ソケットを作成する

関数プロトタイプ:

#include <sys/types.h>
#include <sys/socket.h>
int ソケット(int ドメイン、int タイプ、int プロトコル);

パラメータリスト:

ドメイン パラメータには次の値があります。

AF_INET: IPv4 プロトコル
AF_INET6: IPv6 プロトコル
AF_LOCAL: Unixドメインプロトコル
AF_ROUTE: ルーティングソケット
AF_KEY: キーソケット

タイプの値:

SOCKET_STREAM: 双方向の信頼性の高いデータストリーム(TCPに対応)
SOCKET_DGRAM: 双方向の信頼性のないデータグラム、UDPに対応
SOCKET_RAW: トランスポート層以下のプロトコルを提供し、ICMPメッセージの送受信などの内部ネットワークインターフェースにアクセスできます。

プロトコル値:

タイプがSOCKET_RAWの場合、プロトコルタイプを示すためにこの値を設定する必要があります。他のタイプの場合は、0に設定してください。

この関数は、指定された形式のソケットを作成し、その記述子を返します。成功した場合は記述子が返され、失敗した場合は -1 が返されます。

2. ソケットをバインドする

関数プロトタイプ:

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);

パラメータリスト:

sockfdは以前に作成されたソケット記述子です

my_addr は、一般的なソケット構造体へのポインタです。TCP プロトコル プログラミングを行う場合、通常は sockaddr_in 構造体が使用されます。

構造の内容は次のとおりです。

構造体 socketaddr_in
{
   unsigned short int sin_family; //対応するアドレスファミリIP v4のAF_INTEを入力します
   uint16_t sin_port; //対応するポート番号 struct in_addr sin_addr; //対応するIPアドレス unsigned char sin_zero[8];
};
構造体 in_addr
{
   uint32_t s_addr;
};

addrlen は上記の構造体のサイズであり、sizeof を使用して取得できます。

bind 関数を使用する前に、sockaddr_in タイプの構造体を作成し、その構造体にサーバー情報を保存し、作成したソケットをその構造体にバインドする必要があります。成功した場合は 0 を返し、失敗した場合は -1 を返します。

ポート番号と IP を設定するときは、まず構造体をクリアします。メイン関数がパラメータを渡す場合、対応するポート番号と IP は文字列形式であるため、関数を使用して変換する必要があります。変換形式は次のとおりです。

char port[]="8888"
文字ip[]="192.168.1.1"
構造体 sockaddr_in seraddr'
seraddr.sin_port = htos(atoi(ポート))
seraddr.sin_addr.s_addr = inet_addr(ip);

3. 聞き手を作る。聞く

関数プロトタイプ:

int listen(int fd, int バックログ);

パラメータリスト:

fd は監視対象のソケット記述子です。backlog は監視キューのサイズです。

(1)listen実行後、ソケットはパッシブモードになります。

(2)キューがいっぱいになると、新たな接続要求は拒否されます。クライアントは接続エラー WSAECONNREFUSED を受け取ります。

(3)すでにlisten中のソケットに対してlistenを実行しても効果はありません。

4. 接続が受け入れられるのを待つ

関数プロトタイプ:

#include <sys/socket.h>
 int accept(int s, struct sockaddr * addr, int * addrlen);

bind 関数を比較すると、2 つのパラメータはほぼ同じですが、accept の addr は const によって変更されません。つまり、addr は接続されたクライアントのアドレス情報を保存するために使用され、Yangsaddlen 時に返される addr のサイズです。

したがって、accept 関数は接続されたクライアントのファイル記述子を返し、クライアントのアドレス情報を新しい sockaddr_in 構造体に保存します。接続が失敗した場合は -1 を返します。

5. メッセージの送受信 send and recv

関数プロトタイプ

 int send( SOCKET s, const char FAR *buf, int len, int flags );
int recv( SOCKET s, char FAR *buf, int len, int flags);

この関数のパラメータは次のとおりです。

  • 最初のパラメータは送信側/受信側のソケット記述子を指定します。
  • 2 番目のパラメータは、アプリケーションから送信されるデータを格納するバッファを指定します。
  • 3 番目のパラメータは、実際に送受信されるデータのバイト数を示します。
  • 4 番目のパラメータは通常 0 に設定されます。

送信のプロセス

ここでは、同期ソケットの送信関数の実行フローについてのみ説明します。この関数を呼び出すとき、最初にソケットの送信バッファーの長さで送信されるデータの長さを比較しますSの送信バッファーにデータを送信し始めていないか、Sの送信バッファーには、Sの送信バッファーをレンと比較します。 、プロトコルは、sの送信バッファーの残りのスペースにbufのデータをコピーするだけです。

send 関数がデータを正常にコピーすると、コピーされた実際のバイト数を返します。データのコピー中にエラーが発生した場合、send は SOCKET_ERROR を返します。send がプロトコルによるデータ送信を待機している間にネットワークが切断された場合も、send 関数は SOCKET_ERROR を返します。

送信関数は、buf 内のデータを s の送信バッファの残りのスペースに正常にコピーした後に戻りますが、この時点ではデータが接続のもう一方の端にすぐに送信されない可能性があることに注意してください。プロトコルの後続の送信プロセス中にネットワーク エラーが発生した場合、次の Socket 関数は SOCKET_ERROR を返します。 (send を除くすべての Socket 関数は、ソケットの送信バッファ内のデータがプロトコルによって送信されるまで待機してから、処理を続行する必要があります。待機中にネットワーク エラーが発生した場合、Socket 関数は SOCKET_ERROR を返します)。

recvのプロセス:

ここでは同期ソケットのrecv関数の実行フローについてのみ説明します。アプリケーションが recv 関数を呼び出すと、recv はまず、s の送信バッファ内のデータがプロトコルによって送信されるのを待機します。プロトコルが s の送信バッファ内のデータを送信するときにネットワーク エラーが発生した場合、recv 関数は SOCKET_ERROR を返します。s の送信バッファにデータがない場合、またはプロトコルによってデータが正常に送信された場合、recv はまずソケット s の受信バッファをチェックします。s の受信バッファにデータがない場合、またはプロトコルがデータを受信して​​いる場合、recv はプロトコルがデータを受信するまで待機します。プロトコルがデータの受信を完了すると、recv 関数は s の受信バッファ内のデータを buf にコピーします (プロトコルが受信したデータは buf の長さよりも大きい場合があるため、この場合、s の受信バッファ内のすべてのデータをコピーするには、recv 関数を複数回呼び出す必要があります。recv 関数はデータをコピーするだけで、実際のデータ受信はプロトコルによって完了します)。recv 関数は、実際にコピーされたバイト数を返します。コピー中に recv が失敗した場合は、SOCKET_ERROR を返します。recv 関数がプロトコルによるデータ受信を待機している間にネットワークが中断された場合は、0 を返します。

TCP プロトコル自体は信頼性が高いですが、TCP を使用してデータを送信するアプリケーションが必ずしも信頼できるというわけではありません。ブロックされているかどうかに関係なく、送信サイズは相手側が受信するデータの量を表すものではありません。

ブロッキング モードでは、送信関数のプロセスは、アプリケーションが要求したデータを送信バッファにコピーし、送信して確認後に戻ることです。ただし、送信バッファが存在するため、次のように表されます。送信バッファのサイズが要求されたサイズより大きい場合、送信関数はすぐに戻り、同時にデータをネットワークに送信します。それ以外の場合、送信はバッファに収容できない部分のデータをネットワークに送信し、相手側の確認を待ってから戻ります (受信側が受信バッファでデータを受信すると確認し、アプリケーションが recv を呼び出すのを待つ必要はありません)。

非ブロッキング モードでは、送信関数はデータをプロトコル スタックのバッファにコピーするだけです。バッファ内の使用可能なスペースが不十分な場合は、可能な限りコピーし、成功したコピーのサイズを返します。バッファ内の使用可能なスペースが 0 の場合は、-1 を返し、errno を EAGAIN に設定します。

6.ソケット記述子を閉じる

関数:

閉じる(sockfd);

ファイル操作と同様に、ソケットもファイルであり、使用後は閉じる必要があります。

7. TCPプロトコルに基づくC/Sサーバーモデル

Linux 学習ノート - ネットワーク プログラミング (パート 2)

図解TCPモデル

8. 実装コード

サーバ:

#include <stdio.h>
#include <stdlib.h>
#include <文字列.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
 
typedef struct sockaddr_in SIN;
typedef struct sockaddr SA;
 
int main(int argc,char *argv[])
{
    SIN セラッドル;
    SIN クリアアドレス;
    int len=sizeof(SIN);
    //リスニングソケットを作成します int lisfd=socket(AF_INET,SOCK_STREAM,0);
    if(lisfd<0)
    {
        perror("ソケット");
        終了(0);
    }
    printf("ソケット%dが正常に作成されました\n",lisfd);
    bzero(&seraddr,sizeof(seraddr));
    seraddr.sin_family=AF_INET;
    seraddr.sin_port = htons(8888);
    seraddr.sin_addr.s_addr = inet_addr("192.168.1.6");
    //ソケットをバインド int ret=bind(lisfd,(SA*)(&seraddr),len);
    戻り値<0の場合
    {
        perror("バインド");
        終了(0);
    }
    printf("バインドが成功しました\n");
    //リスニングを開始 ret=listen(lisfd,1024);
    戻り値<0の場合
    {
        perror("聞く");
        終了(0);
    }
    printf("監視は成功しました\n");
    //接続を待機し、接続されたソケット情報を保存します int clifd=accept(lisfd,(SA*)(&cliaddr),(socklen_t *)(&len));
    if(clifd<0)
    {
        perror("受け入れる");
        終了(0);
    }
    printf("クライアント %d が正常に接続されました\n",clifd);
    //読み取りと書き込み char readbuf[1024]={0};
    char送信バッファ[1024]={0};
    ながら(1)
    {
        recv(clifd、readbuf、sizeof(readbuf)、0);
        printf("recv:%s\n",readbuf);
        fgets(sendbuf,sizeof(sendbuf),stdin);
        送信(clifd、送信バッファ、サイズ(送信バッファ)、0);
    }
    //ソケットを閉じます close(clifd);
    閉じる(lisfd);
    0を返します。
}

クライアント:

#include <stdio.h>
#include <stdlib.h>
#include <文字列.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
 
typedef struct sockaddr_in SIN;
typedef struct sockaddr SA;
 
int main(int argc,char *argv[])
{
    SIN セラッドル;
    //リスニングソケットを作成します int serfd=socket(AF_INET,SOCK_STREAM,0);
    if(serfd<0)
    {
        perror("ソケット");
        終了(0);
    }
    printf("ソケット%dが正常に作成されました\n",serfd);
    bzero(&seraddr,sizeof(seraddr));
    seraddr.sin_family=AF_INET;
    seraddr.sin_port = htons(8888);
    seraddr.sin_addr.s_addr = inet_addr("192.168.1.6");
    //接続を要求 int ret=connect(serfd,(SA*)(&seraddr),sizeof(SIN));
    戻り値 == -1 の場合
    {
        perror("接続");
        終了(0);
    }
    printf("接続に成功しました\n");
    //読み取りと書き込み char senbuf[1024]={0};
    char readbuf[1024]={0};
    ながら(1)
    {
        fgets(senbuf,sizeof(senbuf),stdin);
        送信(serfd、senbuf、サイズ(senbuf)、0);
        recv(serfd、readbuf、sizeof(readbuf)、0);
        printf("recv:%s\n",readbuf);
    }
    //ソケットを閉じます close(serfd);
    0を返します。
}

Linux ネットワーク プログラミング機能の簡単な分析に関するこの記事はこれで終わりです。Linux ネットワーク プログラミング機能に関するより関連性の高いコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Linux ネットワーク プログラミング: UDP に基づく信頼性の高いファイル転送の例
  • Linux ネットワーク プログラミング UDP ソケット プログラム例
  • Linux ネットワーク プログラミング ソケット ファイル転送の例
  • Linuxネットワークプログラミングで使用されるネットワーク関数の詳細な説明と使用例
  • Linuxネットワークプログラミングの基本機能を学ぶ

<<:  2つのウェブサイトページ翻訳プラグインの共有

>>:  MySQL でのサブクエリの基本的な使用法

推薦する

Dockerイメージの作成、アップロード、プル、デプロイを理解するための記事

目次1. 画像1. 鏡とは何ですか? 2. 画像の構成と目的(1) Dockerファイル(2)スクラ...

製品を選択した後、右下隅に√記号を表示するための純粋なCSS

おすすめの記事: CSS 疑似クラスの右下隅をクリックすると、選択を示すチェックマークが表示されます...

MySQLでユーザーを作成し、権限を管理する方法

1. ユーザーとパスワードの作成方法1. MySQLデータベースに入る mysql> mysq...

Vue でのテキストエリア適応高さソリューションの実装

目次隠れた問題適応高さのソリューションまず解決策を提示してください。Vueスタックが必要な学生はvu...

Angularコンポーネントの仲介モードの詳細な説明

目次1. 仲介業者モデル2. 例1. 見積コンポーネントに購入ボタンを追加する2. 親コンポーネント...

Linuxは、単一のIPをバインドするためにデュアルネットワークカードを実装するためにボンドを使用します。サンプルコード

ネットワークの高可用性を実現するには、複数のネットワーク カードを仮想ネットワーク カードにバインド...

MySQL でデータの重複挿入を回避する 4 つの方法

最も一般的な方法は、フィールドに主キーまたは一意のインデックスを設定することです。重複データを挿入す...

ウェブサイトにファビコンを追加するためのヒント: URLの前の小さなアイコン

いわゆるファビコンは、Favorites Icon の略で、中国語ではウェブサイトアバターと呼ばれて...

フロントエンド開発における一般的なテクニックのまとめ

1. 記事タイトルリストの右側に日付を表​​示する方法:コードをコピーコードは次のとおりです。 &l...

MySQL 5.7.22 バイナリパッケージのインストールとインストール不要版 Windows 設定方法

次のコードは、MySQL 5.7.22 バイナリ パッケージのインストール方法を紹介しています。具体...

さまざまなブラウザでのhrタグの説明

通常、人事担当者と会うことはめったにありませんが、一度会うと、それが生死を分けることもあります。 H...

IE6 ウェブページ作成リファレンス IE6 デフォルトスタイル

これは実際には IE の公式ドキュメントではありません。他の人が実践を通じて開発した IE6 のデフ...

1 つ以上の Linux インスタンスから SSH キー ペアのバインドを解除します。

キーペアの分離1 つ以上の Linux インスタンスから SSH キー ペアのバインドを解除します。...

この記事では、MySQLのマスタースレーブ同期の原理を説明します。

目次MySQL マスタースレーブ同期原理の簡単な分析1. マスタースレーブとは何ですか? 2. 主従...

HTML テーブル マークアップ チュートリアル (28): セルの境界線の色属性 BORDERCOLOR

テーブルを美しくするために、セルごとに異なる境界線の色を設定できます。基本的な構文<TD 境界...