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 でのサブクエリの基本的な使用法

推薦する

MySql 認証に基づく vsftpd 仮想ユーザー

目次1. MySQLのインストール1.2 テーブル、データベース、ユーザーを作成する1.3 リモート...

MySQL explain クエリ命令情報の取得原理と例

explain はクエリ実行プラン情報を取得するために使用されます。 1. 文法次のように、sele...

Centos7 への mysql8.0rpm のインストール チュートリアル

まず、図をダウンロードしてください 1. まず、centos7に付属しているmariadbをアンイン...

MySQL トランザクションの詳細

目次導入取引の4つの特徴トランザクション分離レベル確認するMVCC現在の読書スナップショット読み取り...

CSS3 弾性拡張ボックスの詳細な説明

使用フレキシブル ボックスはフロントエンドの Web ページ レイアウトで重要な役割を果たしますが、...

MySQL における in と exists の違いの詳細な説明

1. 事前に準備する便宜上、ここで 2 つのテーブルを作成し、そこにいくつかのデータを追加します。果...

JS は Web ページナビゲーションバーの特殊効果を実現します

この記事では、ネイティブ JS を使用して実装された実用的な Web ナビゲーション バー効果を紹介...

デスクトップ仮想化を実現するために Hyper-V を展開する手順 (グラフィック チュートリアル)

Hyper-V を展開するためのハードウェア要件は次のとおりです。 64 ビット プロセッサ、具体...

Windows 10 での MySQL 8.0.12 解凍バージョンのインストール グラフィック チュートリアル

この記事は、MySQL 8.0.12解凍版のインストールグラフィックチュートリアルを記録しています。...

Portainer を使用した Docker コンテナのデプロイのプロジェクト実践

目次1. 背景2. 操作手順3. Portinerをインストールする3.1 Dockerのデプロイメ...

Docker イメージのデフォルトの保存場所を変更する方法 (ソリューション)

システムの初期のパーティション分割により、オペレーティング システム内の対応する / パーティション...

CentOS7 に YUM 経由で MySQL 5.7 をインストールする詳細な手順

1. インストールパッケージを保存する場所に移動しますcd /home/lnmp 2. MySQL ...

Docker コマンドラインの完全ガイド (知っておくべき 18 のこと)

序文Docker イメージは Dockerfile といくつかの必要な依存関係で構成され、Docke...

Docker で onlyoffice をインストールして展開する詳細なプロセス

0. システム要件CPU I5-10400F以上メモリ 16 GB、32 GBのメモリが最適ハードド...

MySQL スケジュールされたデータベース バックアップ操作の例

この記事では、MySQL のスケジュールされたデータベース バックアップ操作の例について説明します。...