Правильно закройте файловый дескриптор при открытии через сетевое монтирование - PullRequest
1 голос
/ 08 октября 2019

В настоящее время я пытаюсь выяснить, как правильно закрыть дескриптор файла, когда он указывает на удаленный файл и соединение потеряно.

У меня есть простой пример программы, которая открывает дескриптор файла наsshfs смонтируйте папку и начните запись в файл.

Я не могу найти способ обработки случая, когда соединение потеряно.

void *write_thread(void* arg);

int main()
{
    pthread_t thread;
    int fd = -1;

    if(-1 == (fd = open("/mnt/testfile.txt", O_CREAT | O_RDWR | O_NONBLOCK, S_IRWXU)))
    {
        fprintf(stderr, "Error oppening file : %m\n");
        return EXIT_FAILURE;
    }
    else
    {
        if(0 > pthread_create(&thread, NULL, write_thread, &fd))
        {
            fprintf(stderr, "Error launching thread : %m\n");
            return EXIT_FAILURE;
        }
        fprintf(stdout, "Waiting 10 seconds before closing\n");
        sleep(10);
        if(0 > close(fd))
        {
            fprintf(stderr, "Error closing file descriptor: %m\n");
        }
    }
}

void *write_thread(void* arg)
{
    int fd = *(int*)arg;
    int ret;

    while(1)
    {
        fprintf(stdout, "Write to file\n", fd);
        if(0 > ( ret = write(fd, "Test\n", 5)))
        {
            fprintf(stderr, "Error writing to file : %m\n");
            if(errno == EBADF)
            {
                if(-1 == close(fd))
                {
                    fprintf(stderr, "Close failed : %m\n");
                }
                return NULL;
            }
        }
        else if(0 == ret)
        {
            fprintf(stderr, "Nothing happened\n");
        }
        else
        {
            fprintf(stderr, "%d bytes written\n", ret);
        }
        sleep(1);
    }
}

Когда соединение потеряно (то есть я отключаю кабель Ethernet между моими платами), close в главном потоке всегда блокирует, использую ли я флаг O_NONBLOCK или нет.

Иногда вызов записи завершается с ошибкой EBADF или продолжается в течениедолгое время до сбоя.

Моя проблема в том, что вызов write не всегда завершается неудачно, когда соединение теряется, поэтому я не могу вызвать событие в потоке и не могу запустить его из основногонить, потому что close блокирует навсегда.

Итак, мой вопрос: Как правильно обработать этот случай в C?

Ответы [ 3 ]

2 голосов
/ 08 октября 2019

вопрос такой: как правильно разобраться с этим делом в C?

Просто не можете. Файловые дескрипторы разработаны так, чтобы быть унифицированными и простыми, независимо от того, на что они указывают. Когда устройство монтируется и соединение (физическое или виртуальное) с ним обрывается, все становится сложно даже на уровне командной строки.

1 голос
/ 08 октября 2019

Существует фундаментальная проблема с удаленными файловыми системами, где, с одной стороны, необходимо кэшировать данные, чтобы производительность оставалась на приемлемом уровне, а с другой стороны, кэширование в нескольких клиентах может привести к конфликтам, которые не виднынапример, сервер.

NFS выбирает кэширование по умолчанию, и если кэш загрязнен, он просто зависает до возобновления соединения.

Документация для sshfs предлагаетпохожее поведение.

Исходя из grepping исходного кода sshfs , кажется, что он вообще не поддерживает O_NONBLOCK.

Ничто из этого не имеет ничего общего сC.

IMO ваш лучший вариант - переключиться на nfs и смонтировать, например, с помощью -o soft -o timeo=15 -o retrans=1.

. Это может привести к повреждению / потере данных в определенных ситуациях, когдаэто отключение от сети, в основном, когда есть несколько клиентов или когда происходит сбой клиента, но он поддерживает O_NONBLOCK и в любом случае вернет EIO, если соединение потеряно во время запросаЕсть в полете.

0 голосов
/ 09 октября 2019

После некоторого поиска я обнаружил, что монтирование SSH может быть настроено на разрыв соединения и отключение от сервера, если ничего не происходит.


Настройка ServerAliveInterval X на стороне клиента дляотключить, если сервер не отвечает через X секунд.

Настройка ClientAliveCountMax X на стороне сервера для отключения, если клиент не отвечает через X секунд.

ServerAliveCountMax Y и ClientAliveCountMax Y также можно использовать для повторной попытки Y раз перед разрывом соединения.


При применении этой конфигурации монтирование sshfs автоматически удаляется Linux, когдасоединение не отвечает.

В этой конфигурации вызов write завершается с ошибкой сначала Input/output error, а затем Transport endpoint is not connected.

Этого достаточно, чтобы обнаружить, что соединение потеряно итаким образом убирая беспорядок перед выходом.

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