GNU/Linux >> Linux の 問題 >  >> Linux

Linux ソケットの POLLERR、POLLHUP、POLLNVAL を処理するにはどうすればよいですか?

POLLNVAL ファイル記述子の値が無効であることを意味します。通常はプログラムのエラーを示しますが、poll に頼ることができます POLLNVAL を返す ファイル記述子を閉じて、それ以降ファイルを開いていない場合、記述子を再利用した可能性があります。

POLLERR select からのエラー イベントに似ています . read であることを示します または write 呼び出しはエラー状態 (I/O エラーなど) を返します。これには、select の帯域外データは含まれません。 errorfds 経由で信号を送る マスクしますが poll POLLPRI 経由のシグナル .

POLLHUP 基本的に、接続のもう一方の端にあるものが接続の端を閉じたことを意味します。 POSIX では

<ブロック引用>

デバイスが切断されました。このイベントと POLLOUT は相互に排他的です。ハングアップが発生した場合、ストリームを書き込み可能にすることはできません。

これは端末にとって十分明らかです:端末がなくなった (SIGHUP を生成する同じイベント:モデム セッションが終了した、端末エミュレータ ウィンドウが閉じられたなど)。 POLLHUP 通常のファイルに対して送信されることはありません。パイプとソケットの場合は、オペレーティング システムによって異なります。 Linux は POLLHUP を設定します パイプの書き込み側のプログラムがパイプを閉じ、POLLIN|POLLHUP を設定したとき ソケットのもう一方の端がソケットを閉じたが、POLLIN ソケットのシャットダウンの場合のみ。最近の *BSD セット POLLIN|POLLUP パイプの書き込み側がパイプを閉じ、ソケットの動作がより可変になる場合。


POLLHUP ソケットが接続されていないことを意味します。 TCP では、これは FIN が送受信されたことを意味します。

POLLERR ソケットで非同期エラーが発生したことを意味します。 TCP では、これは通常、RST が受信または送信されたことを意味します。ファイル記述子がソケットでない場合、POLLERR デバイスがポーリングをサポートしていない可能性があります。

上記の両方の条件で、ソケット ファイル記述子はまだ開いており、まだ閉じられていません (しかし shutdown() 既に呼び出されている可能性があります)。 close() ファイル記述子で、ソケットに代わってまだ予約されているリソースを解放します。理論的には、ソケットをすぐに再利用できるはずです (たとえば、別の connect() 呼び出します)

POLLNVAL ソケットファイル記述子が開いていないことを意味します。 close() にするとエラーになります


それは正確なエラーの性質に依存します。 getsockopt() を使用して問題を確認してください:

int error = 0;
socklen_t errlen = sizeof(error);
getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen);

値:http://www.xinotes.net/notes/note/1793/

最も簡単な方法は、ソケットがいずれにしても使用できなくなったと想定して閉じることです。


最小限の FIFO の例

これらの状況がいつ発生するかを理解すれば、対処法も簡単にわかるはずです。

poll.c

#define _XOPEN_SOURCE 700
#include <fcntl.h> /* creat, O_CREAT */
#include <poll.h> /* poll */
#include <stdio.h> /* printf, puts, snprintf */
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
#include <unistd.h> /* read */

int main(void) {
    char buf[1024];
    int fd, n;
    short revents;
    struct pollfd pfd;

    fd = open("poll0.tmp", O_RDONLY | O_NONBLOCK);
    pfd.fd = fd;
    pfd.events = POLLIN;
    while (1) {
        puts("loop");
        poll(&pfd, 1, -1);
        revents = pfd.revents;
        if (revents & POLLIN) {
            n = read(pfd.fd, buf, sizeof(buf));
            printf("POLLIN n=%d buf=%.*s\n", n, n, buf);
        }
        if (revents & POLLHUP) {
            printf("POLLHUP\n");
            close(pfd.fd);
            pfd.fd *= -1;
        }
        if (revents & POLLNVAL) {
            printf("POLLNVAL\n");
        }
        if (revents & POLLERR) {
            printf("POLLERR\n");
        }
    }
}

GitHub アップストリーム。

コンパイル:

gcc -o poll.out -std=c99 poll.c

使い方:

sudo mknod -m 666 poll0.tmp p
./poll.out

別のシェル:

printf a >poll0.tmp

ポルハップ

ソースを変更しない場合:./poll.out 出力:

loop
POLLIN n=1 buf=a
loop
POLLHUP
loop

そう:

  • POLLIN 入力が利用可能になったときに発生
  • POLLHUP ファイルが printf によって閉じられたときに発生します
  • close(pfd.fd);pfd.fd *= -1; クリーンアップすると、POLLHUP の受信が停止します
  • poll 永久にハングアップ

これは通常の操作です。

次の open を待つために FIFO を再登録できるようになりました。 、または完了したらループを終了します。

世論調査

pfd.fd *= -1; をコメントアウトすると :./poll.out プリント:

POLLIN n=1 buf=a
loop
POLLHUP
loop
POLLNVAL
loop
POLLNVAL
...

永遠にループします。

そう:

  • POLLINPOLLHUPclose 以前のように起こった
  • pfd.fd を設定していないため 負の数 poll fd を使用しようとし続けます
  • これは POLLNVAL を返し続けます 永遠に

したがって、これは発生すべきではなかったことがわかり、コードにバグがあることを示しています。

ポーラー

POLLERR を生成する方法がわかりません FIFOで。方法があれば教えてください。しかし、file_operations で可能なはずです

Ubuntu 14.04 でテスト済み。


Linux
  1. Linuxのソケットバッファサイズを見つける方法

  2. Linux でファイルとディレクトリのサイズを確認するにはどうすればよいですか?

  3. Linux でソケット接続のアップタイムを確認する方法

  1. Linuxが遅いコンピューター(そして地球)を救う方法

  2. Linux で入出力エラーを解釈して修正する方法は?

  3. Linux システムの Spectre および Meltdown の脆弱性を軽減する方法は?

  1. Linuxターミナルでディレクトリを開いたり閉じたりする方法

  2. Linuxで動的ライブラリと静的ライブラリを処理する方法

  3. Linuxでエイリアスを作成してエイリアスコマンドを使用する方法