очистка в SIGPIPE - PullRequest
       10

очистка в SIGPIPE

1 голос
/ 04 декабря 2010

У меня есть пул сокетных подключений, которые совместно используются в нескольких потоках, мертвое соединение должно быть удалено из пула, проблема в том, что я не знаю, какой из них мертв из SIGPIPE sighandler, Есть ли какие-либо советы в этой ситуации?

Ответы [ 2 ]

5 голосов
/ 04 декабря 2010

Один из способов справиться с этим - игнорировать SIGPIPE. Это означает, что ваша операция записи (write, sendmsg, что угодно) будет возвращаться с ошибкой, и, если вы обратите внимание на возвращаемую ошибку, вы будете знать, какой файловый дескриптор дает сбой - потому что все синхронно. 1003 *

0 голосов
/ 19 июля 2013

Следующие программы не имеют ничего общего с сокетами, вместо этого они используют именованные каналы.Просто приведу здесь программу, чтобы продемонстрировать, как я справился с вышеуказанным вопросом.Это пара программ, которые я написал, чтобы лучше понять именованные каналы.Все условия ошибки обрабатываются.Есть два исполняемых файла, которые должны быть скомпилированы отдельно.Запустите каждый исполняемый файл в двух отдельных терминалах на одном компьютере.Порядок их запуска не важен.Какой из них запускается первым, будет создан именованный канал, а другой при запуске заметит, что он уже создан (обработка ошибок mkfifo).Автор пишет в канал один раз в секунду, а читатель читает из канала всякий раз, когда read () возвращает.На стороне писателя SIGPIPE игнорируется и вместо этого обрабатывается EPIPE.Нажмите q на клавиатуре в любом из двух окон терминала (считыватель или записывающее устройство), и оба закроются.

Если SIGPIPE не игнорируется, то произойдет, что, когда я выйду из считывателя передпишущий (нажав q в терминале считывателя), write () завершится ошибкой и вызовет сигнал SIGPIPE, который будет получен приложением писателя.Поведение по умолчанию - немедленный выход из приложения.Это, конечно, не то, что мне нужно в многопоточном приложении, которое собиралось использовать этот код.Поэтому я проигнорировал сигнал, проверил на предмет ошибки и обработал его соответствующим образом.

writer.c:

#include <stdio.h>      //for printf()
#include <stdlib.h>     //for malloc()
#include <stdint.h>     //for definitions of uint8_t etc..
#include <unistd.h>     //for sleep()
#include <sys/stat.h>   //for S_IRUSR, S_IWUSR, mkfifo()
#include <fcntl.h>      //for O_WRONLY
#include <errno.h>      //for errno, perror()
#include "kbhit.h"
#include <sys/types.h>
#include <signal.h>     //for signal()

/* Named pipe considerations (http://www.unixguide.net/unix/programming/2.10.3.shtml):
 *
 * To use the pipe, you open it like a normal file, and use read()
 * and write() just as though it was a plain pipe.
 * However, the open() of the pipe may block. The following rules apply:
 *
 * If you open for both reading and writing (O_RDWR), then the open will not block.
 *
 * If you open for reading (O_RDONLY), the open will block until
 * another process opens the FIFO for writing, unless O_NONBLOCK is
 * specified, in which case the open succeeds.
 *
 * If you open for writing O_WRONLY, the open will block until
 * another process opens the FIFO for reading, unless O_NONBLOCK is
 * specified, in which case the open fails.
 *
 * When reading and writing the FIFO, the same considerations apply as for
 * regular pipes and sockets, i.e. read() will return EOF when all
 * writers have closed, and write() will raise SIGPIPE when
 * there are no readers. If SIGPIPE is blocked or ignored, the call
 * fails with EPIPE.
 *
 */


static const char file_path[] = "/tmp/anurag";
static const char message[] = "Hello from writer!";

int main(void) {
    int ret;
    int fd=0;
    char keypress=0;

    /*
     * (/3219723/ochistka-v-sigpipe)
     * EPIPE is returned if fd is connected to a pipe or socket whose reading end is closed.
     * When this happens the writing process will also receive a SIGPIPE signal.
     * (Thus, the write return value is seen only if the program catches, blocks or ignores this signal.)
     */
    signal(SIGPIPE, SIG_IGN);

    //Create the FIFO (named pipe)
    ret = mkfifo(file_path, S_IRUSR | S_IWUSR);

    if(ret == 0) {
        printf("mkfifo(): Named pipe created.\n");
    } else {
        if ((ret == -1) && (errno == EEXIST)) {
            perror("mkfifo()");
        } else {
            perror("mkfifo()");
        }
    }
    printf("Will now begin waiting on open()...\n");
    fd = open(file_path, O_WRONLY);
    if(fd == -1) {
        perror("open()");
    } else if (fd > 0) {
        printf("open(): Named pipe file descriptor opened for writing.\n");
    }


    while(keypress != 'q') {
        if (kbhit()) {
            keypress = getchar();
            printf("Exiting...\n");
        } else {
            ret = write(fd, message, sizeof(message));
            if(ret > 0) {
                printf("write(): %d bytes to pipe: %s\n",ret,message);
            } else if (ret <=0) {
                if(errno == EPIPE) {
                    printf("write(): got EPIPE, reader closed the pipe, exiting...\n");
                    break;
                } else {
                    perror("write()");
                    break;
                }
            }
        }
        sleep(1);
    };

    ret = close(fd);
    if(ret == 0) {
        printf("close(): Named pipe file descriptor closed.\n");
    } else {
        perror("close()");
    }

    ret = remove(file_path);
    if(ret == 0) {
        printf("remove(): Named pipe deleted.\n");
    } else {
        perror("remove()");
    }
    fflush(stdout);
    fflush(stderr);
    return EXIT_SUCCESS;
}

reader.c:

#include <stdio.h>      //for printf()
#include <stdlib.h>     //for malloc()
#include <stdint.h>     //for definitions of uint8_t etc..
#include <unistd.h>     //for sleep()
#include <sys/stat.h>   //for S_IRUSR, S_IWUSR, mkfifo()
#include <fcntl.h>      //for O_WRONLY
#include <errno.h>      //for errno, perror()
#include <string.h>     //for memset()
#include "kbhit.h"

/* Named pipe considerations (http://www.unixguide.net/unix/programming/2.10.3.shtml):
 *
 * To use the pipe, you open it like a normal file, and use read()
 * and write() just as though it was a plain pipe.
 * However, the open() of the pipe may block. The following rules apply:
 *
 * If you open for both reading and writing (O_RDWR), then the open will not block.
 *
 * If you open for reading (O_RDONLY), the open will block until
 * another process opens the FIFO for writing, unless O_NONBLOCK is
 * specified, in which case the open succeeds.
 *
 * If you open for writing O_WRONLY, the open will block until
 * another process opens the FIFO for reading, unless O_NONBLOCK is
 * specified, in which case the open fails.
 *
 * When reading and writing the FIFO, the same considerations apply as for
 * regular pipes and sockets, i.e. read() will return EOF when all
 * writers have closed, and write() will raise SIGPIPE when
 * there are no readers. If SIGPIPE is blocked or ignored, the call
 * fails with EPIPE.
 *
 */


static const char file_path[] = "/tmp/anurag";
static char message[100] = {0};

int main(void) {
    int ret;
    int fd=0;
    char keypress=0;
    //Create the FIFO (named pipe)
    ret = mkfifo(file_path, S_IRUSR | S_IWUSR);

    if(ret == 0) {
        printf("mkfifo(): Named pipe created.\n");
    } else {
        if ((ret == -1) && (errno == EEXIST)) {
            perror("mkfifo()");
        } else {
            perror("mkfifo()");
        }
    }
    printf("Will now begin waiting on open()...\n");
    fd = open(file_path, O_RDONLY);
    if(fd == -1) {
        perror("open()");
    } else if (fd > 0) {
        printf("open(): Named pipe file descriptor opened for reading.\n");
    }


    while(keypress != 'q') {
        if (kbhit()) {
            keypress = getchar();
            printf("Exiting...\n");
        } else {
            memset(message,0,100);
            ret = read(fd, message, 100);
            if(ret > 0) {
                printf("read(): %d bytes from pipe: %s\n",ret, message);
            } else if (ret == 0){
                printf("read(): got EOF, writer closed the pipe, exiting...\n");
                break;
            } else if (ret < 0){
                perror("read()");
                break;
            }
        }
        sleep(1);
    };

    ret = close(fd);
    if(ret == 0) {
        printf("close(): Named pipe file descriptor closed.\n");
    } else {
        perror("close()");
    }

    ret = remove(file_path);
    if(ret == 0) {
        printf("remove(): Named pipe deleted.\n");
    } else {
        perror("remove()");
    }
    fflush(stdout);
    fflush(stderr);
    return EXIT_SUCCESS;
}

В обоих приведенных выше файлах c используется kbhit () для опроса символов, полученных с клавиатуры.Вот код для этого:

kbhit.c:

//Taken from: http://cboard.cprogramming.com/c-programming/63166-kbhit-linux.html

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include "kbhit.h"

int kbhit(void) {
    struct termios oldt, newt;
    int ch;
    int oldf;

    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

    ch = getchar();

    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    fcntl(STDIN_FILENO, F_SETFL, oldf);

    if (ch != EOF) {
        ungetc(ch, stdin);
        return 1;
    }

    return 0;
}

kbhit.h:

#ifndef KBHIT_H_
#define KBHIT_H_

//Console related variables and functions
int kbhit(void);

#endif /* KBHIT_H_ */
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...