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

推薦する

Navicat PremiumでSQLファイルをインポートする方法

今日、最終プロジェクトに取り組み始めましたが、今年はMySQLデータベースを使用したため、Navic...

Windows 10 システムで nginx ファイル サーバーを構成するためのグラフィック チュートリアル

Nginx の公式 Web サイトから Windows バージョンの Nginx をダウンロードしま...

MySql 8.0 と対応するドライバー パッケージの一致に関する注意事項

MySql 8.0 対応ドライバパッケージのマッチングMySql データベースをバージョン 8.0 ...

VMware 仮想マシンのインストール Linux システムのグラフィック チュートリアル

この記事では、LinuxシステムのVMwareインストールの具体的な手順を参考までに紹介します。具体...

Js における new 演算子の役割の詳細な説明

序文Js は現在最も一般的に使用されているコード操作言語であり、その中でも new 演算子は特によく...

JS ES6 変数分割代入の詳細な説明

目次1. 脱構築とは何か? 2. 配列の分割3. 配列モードと代入モードの統一4. デフォルト値の構...

SpringBoot のパッケージ化と Docker へのアップロード、およびマルチインスタンス デプロイメントの実装に関する簡単な分析 (IDEA バージョン)

最近友人からDockerを触ったことがあるかと聞かれました。あまり自信がなかったので答えられませんで...

Dockerはmacvlanをベースにホスト間コンテナ通信を実装する

2 台のテスト マシンを見つけます。 [root@docker1 centos_zabbix]# d...

MySQLとRedisでセカンダリキャッシュを実装する方法の詳細な説明

Redis の紹介Redis は完全にオープンソースで無料であり、BSD プロトコルに準拠しており、...

JavaScript はマウスのドラッグを実装して div のサイズを調整します

この記事では、マウスをドラッグしてdivのサイズを調整するJavaScriptの具体的なコードを参考...

CSS を使用して物流の進行状況のスタイルを実装するためのサンプルコード

効果: CSS スタイル: <スタイル タイプ="text/css">...

JavaScriptのvar let constの違いは何ですか?

目次1. 繰り返し宣言1.1 変数1.2 しましょう1.3 定数2. 可変プロモーション2.1 変数...

Apache FlinkCEP でタイムアウトステータス監視を実装するための詳細な手順

CEP - 複合イベント処理。ご注文後、一定期間内にお支払いの確認が取れませんでした。タクシーの配...

ゲーム着物メモ問題の簡単な分析

本日、ゲームを再起動した後、バックアップしたデータをターゲットデータベースにインポートできないことが...

MySQL の自動増分 ID に関するいくつかの小さな問題の要約

以下の質問はすべて InnoDB ストレージ エンジンに基づいています。 1. 最も大きな ID を...