Linux IO 多重化 epoll ネットワーク プログラミング

Linux IO 多重化 epoll ネットワーク プログラミング

序文

この章では、基本的な Linux 関数と epoll 呼び出しを使用して、Linux 上で実行できる完全なサーバーおよびクライアントの例を記述します。クライアントとサーバーの機能は次のとおりです。

  • クライアントは標準入力から行を読み取り、それをサーバーに送信します。
  • サーバーはネットワークから行を読み取り、クライアントに出力します。
  • クライアントはサーバーからの応答を受信し、この行を標準出力に出力します。

サーバ

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

#include <unistd.h>
#include <sys/types.h> /* 基本的なシステムデータ型 */
#include <sys/socket.h> /* 基本的なソケット定義 */
#include <netinet/in.h> /* sockaddr_in{} およびその他のインターネット定義 */
#include <arpa/inet.h> /* inet(3) 関数 */
#include <sys/epoll.h> /* epoll関数 */
#include <fcntl.h> /* 非ブロッキング */
#include <sys/resource.h> /*setrlimit */
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <文字列.h>
#定義 MAXEPOLLSIZE 10000
#定義 MAXLINE 10240
int ハンドル(int 接続);
int setnonblocking(int sockfd)
{
  (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) の場合 {
    -1 を返します。
  }
  0を返します。
}
int main(int argc, char **argv)
{
  int servPort = 6888;
  整数 listenq = 1024;
  int listenfd、connfd、kdpfd、nfds、n、nread、curfds、acceptCount = 0;
  構造体 sockaddr_in servaddr、cliaddr;
  socklen_t socklen = sizeof(struct sockaddr_in);
  構造体 epoll_event ev;
  構造体epoll_eventイベント[MAXEPOLLSIZE];
  構造体rlimitrt;
  char buf[MAXLINE];
  /* 各プロセスが開くことができるファイルの最大数を設定します */
  rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
  (setrlimit(RLIMIT_NOFILE, &rt) == -1)の場合 
  {
    perror("setrlimitエラー");
    -1 を返します。
  }
  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET; 
  servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
  servaddr.sin_port = htons(servPort);
  listenfd = socket(AF_INET、SOCK_STREAM、0); 
  (listenfd == -1)の場合{
    perror("ソケットファイルを作成できません");
    -1 を返します。
  }
  整数オプト = 1;
  setsockopt(listenfd、SOL_SOCKET、SO_REUSEADDR、&opt、sizeof(opt));
  (setnonblocking(listenfd) < 0) の場合 {
    perror("setnonblockエラー");
  }
  (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) == -1)の場合 
  {
    perror("バインドエラー");
    -1 を返します。
  } 
  (listen(listenfd, listenq) == -1)の場合 
  {
    perror("エラーを聞く");
    -1 を返します。
  }
  /* epoll ハンドルを作成し、リスニング ソケットを epoll セットに追加します */
  kdpfd = epoll_create(MAXEPOLLSIZE);
  ev.events = EPOLLIN | EPOLLET;
  ev.data.fd = listenfd;
  (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listenfd, &ev) < 0 の場合) 
  {
    fprintf(stderr, "epoll セット挿入エラー: fd=%d\n", listenfd);
    -1 を返します。
  }
  曲線 = 1;
  printf("epollserver の起動、ポート %d、最大接続数は %d、バックログは %d\n", servPort、MAXEPOLLSIZE、listenq);
  のために (;;) {
    /* イベントが発生するのを待つ */
    nfds = epoll_wait(kdpfd、イベント、curfds、-1);
    (nfds == -1)の場合
    {
      perror("epoll_wait");
      続く;
    }
    /* すべてのイベントを処理する */
    (n = 0; n < nfds; ++n)の場合
    {
      if (events[n].data.fd == listenfd) 
      {
        connfd = accept(listenfd、(struct sockaddr *)&cliaddr、&socklen);
        (接続数 < 0)の場合 
        {
          perror("エラーを受け入れる");
          続く;
        }
        sprintf(buf, "フォーム%sを受け入れます:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
        printf("%d:%s", ++acceptCount, buf);

        (curfds >= MAXEPOLLSIZE)の場合{
          fprintf(stderr, "接続が多すぎます。%d\n 以上です", MAXEPOLLSIZE);
          close(接続);
          続く;
        } 
        (setnonblocking(connfd) < 0) の場合 {
          perror("setnonblockingエラー");
        }
        ev.events = EPOLLIN | EPOLLET;
        ev.data.fd = connfd;
        (epoll_ctl(kdpfd, EPOLL_CTL_ADD, connfd, &ev) < 0 の場合)
        {
          fprintf(stderr, "ソケット '%d' を epoll に追加できませんでした: %s\n", connfd, strerror(errno));
          -1 を返します。
        }
        カーフds++;
        続く;
      } 
      // クライアント要求を処理する if (handle(events[n].data.fd) < 0) {
        epoll_ctl(kdpfd、EPOLL_CTL_DEL、イベント[n].data.fd、&ev);
        curfds--;
      }
    }
  }
  listenfdを閉じます。
  0を返します。
}
int ハンドル(int 接続) {
  int 読み取り;
  char buf[MAXLINE];
  nread = read(connfd, buf, MAXLINE); //クライアントソケットストリームを読み取る if (nread == 0) {
    printf("クライアントは接続を閉じます\n");
    close(接続);
    -1 を返します。
  } 
  (nread < 0) の場合 {
    perror("読み取りエラー");
    close(接続);
    -1 を返します。
  }  
  write(connfd, buf, nread); //クライアントに応答する return 0;
}

コンパイル

サーバーをコンパイルして起動する

gcc epollserver.c -o epollserver
./epollserver

要約する

以上がこの記事の全内容です。この記事の内容が皆様の勉強や仕事に何らかの参考学習価値をもたらすことを願います。123WORDPRESS.COM をご愛顧いただき、誠にありがとうございます。これについてもっと知りたい場合は、次のリンクをご覧ください。

以下もご興味があるかもしれません:
  • Linux IOの詳細な紹介
  • Linux で iostat コマンドを使用するチュートリアル
  • Linux のソケット IO モデルの興味深い説明
  • Linux の 5 つの IO モデルの詳細な紹介
  • Linux の高性能ネットワーク IO と Reactor モデルの分析

<<:  JavaScript で最も高速なループはどれですか?

>>:  MySQL 圧縮の使用シナリオとソリューション

推薦する

5 分で vue-cli3 を使用してプロジェクトを作成する方法を説明します (初心者向けガイド)

目次1. Vue環境を構築する2. Vue スキャフォールディングツール3. プロジェクトを作成する...

HTML ヘッドタグの詳細な紹介

HTML のヘッド部分には、ブラウザによる Web ページのレンダリングや SEO などに関連するタ...

Dockerコンテナが外部ネットワークにpingできない問題を解決する

今日、docker で redis 環境を構築していたところ、yum がリソースを取得できず、インタ...

HTML のオートコンプリートを無効にして履歴を表示しないようにする

入力ボックスには、コンテンツを入力するときに常に入力履歴が表示されます。これを無効にする現在の方法は...

css-loader を使用して vue-cli で css モジュールを実装する

【序文】 Vue と React の CSS モジュール ソリューションはどちらも、実装にローダーに...

Nginxを使用してストリーミングメディアサーバーを構築し、ライブブロードキャスト機能を実現する

前面に書かれた近年、ライブストリーミング業界は非常に人気が高まっています。伝統的な業界でのライブスト...

異なるインデックスを更新してMySQLのデッドロックルーチンを解決する

前回の記事では、ソース コードを使用してロック関連の情報をデバッグする方法を紹介しました。ここでは、...

MySQL でパーセンテージと最初の数パーセントを表示する方法

目次必要とする実装コードデータベース数日前、友人からこれを書くのを手伝ってほしいと頼まれました。ただ...

MySQLにデータを素早くインポートする方法

序文:日々の勉強や仕事の中で、データをエクスポートする必要に迫られることがよくあります。たとえば、デ...

アルバムと写真をアルバムに保存するためのWeChatアプレット

私は現在、Xiao Nian Gao に似たビデオおよびツール アプリを開発しています。ユーザーが作...

リンクをクリックしたときに表示される点線のボックスを削除するいくつかの方法

削除する方法はいくつかあります:リンクを直接追加するonfocus="this.blur(...

テーブルを使用する場合と CSS を使用する場合 (経験の共有)

TW のメインテキスト ページは、以前は小さなモニターと低解像度のユーザーを考慮して幅が 850 ピ...

SpringBoot と Docker の統合の詳細なプロセス

目次1. デモプロジェクト1.1 インターフェースの準備1.2 構成の準備2. Dockerがリモー...

React+Koa によるファイルアップロードの実装例

目次背景サーバーの依存関係バックエンド構成クロスドメインバックエンド構成の静的リソースアクセスではk...

8 JSのreduce使用例とreduce操作方法

reduceメソッドは配列の反復メソッドです。 mapやfilterとは異なり、 reduceメソッ...