recvmsg () случайным образом возвращает EWOULDBLOCK - PullRequest
0 голосов
/ 27 февраля 2019

У меня есть набор программ клиент-сервер TCP, который работает без проблем более 10 лет.Задание 'head' порождает тело дочерних процессов (я на платформе AS400, которая не поддерживает fork () / exec ()).Головное задание настраивается в качестве TCP-сервера, и, как только устанавливается соединение, оно сразу же раздает соединение с одним из дочерних заданий с помощью sendmsg ().Используется обычный шаблон socketpair () и т. Д.Я признаю, что когда я собирал все это вместе 12 лет назад, я не понимал всего, что происходило.Код, который я нашел для пропуска открытого соединения, приведен ниже.Итак, головное задание ожидает вызова accept () и вызывает sendfd (), когда accept () возвращает.

int sendfd(int s, int fd)
{
    char buf[1];
    struct iovec iov;
    struct msghdr msg;
    struct cmsghdr *cmsg;
    int n;
    char cms[CMSG_SPACE(sizeof(int))];

    buf[0] = 0;
    iov.iov_base = buf;
    iov.iov_len = 1;

    memset(&msg, 0, sizeof msg);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = (caddr_t)cms;
    msg.msg_controllen = CMSG_LEN(sizeof(int));

    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    memmove(CMSG_DATA(cmsg), &fd, sizeof(int));

    if ((n = sendmsg(s, &msg, 0)) != iov.iov_len) {
        return -1;
    }
    return 0;
}

Итак, дочерние задания запускают подпрограмму для получения соединения.Это ниже.Пул дочерних процессов эффективно выполняет эту подпрограмму наподобие "recvfd (0);"В нашем отделе обеспечения качества будет проведен автоматизированный тест, и с прошлой недели весь набор дочерних процессов умрет, по-видимому, случайным образом, с точностью до секунды, с EWOULDBLOCK.Я смущен этой ошибкой.recvmsg () всегда блокируется, ожидая сообщения.Ошибка относится к принимаемому сокету или к «0», для которого он используется?Ничто в моем коде не меняет качества файлового дескриптора 0. Я действительно удивлен, почему умирает весь набор дочерних процессов.Что-то говорит мне, что дескриптор файла 0 изменяется, но в коде нет ничего для любой программы, которая делает какие-либо манипуляции, подобные этой.

int recvfd(int s)
{
    int ret, fd;
    char buf[1];
    struct iovec iov;
    struct msghdr msg;
    struct cmsghdr *cmsg;
    char cms[CMSG_SPACE(sizeof(int))];

    iov.iov_base = buf;
    iov.iov_len = 1;

    memset(&msg, 0, sizeof msg);
    msg.msg_name = 0;
    msg.msg_namelen = 0;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    msg.msg_control = (caddr_t)cms;
    msg.msg_controllen = sizeof cms;

    if ((ret = recvmsg(s, &msg, 0)) < 0) {
        return -1;
    }

    if (ret == 0) {
        return -1;
    }

    cmsg = CMSG_FIRSTHDR(&msg);
    memmove(&fd, CMSG_DATA(cmsg), sizeof(int));

    return fd;
}

Я могу опубликовать больше кода, если потребуется больше подробностей.Я должен найти эту ошибку сразу, так как она является ядром нашего бизнеса.Заранее спасибо!

РЕДАКТИРОВАТЬ: Вот фрагмент из дочернего кода.Посмотрите, что 'worker_sd' явно установлен на 0. Проблема, которую мне нужно исправить, состоит в том, что выход из цикла означает выход из программы, но я не знаю, есть ли способ справиться с этой ошибкой.

сообщение об ошибке в конечном итоге будет: дочерний объект транзакции завершается с new_sock = -1 и ошибкой = операция привела бы к приостановке процесса.

// worker_sd is explicitly set to 0 because the parent set the child's 0 file descriptor (the usual one
// reserved for standard input) to be the socket over which open descriptors come.
int worker_sd = 0;

jobSwitches.get();
logging_on = jobSwitches[QQJobSwitches::LOGGING_ON] == '1';
debug_on = jobSwitches[QQJobSwitches::DEBUG_ON] == '1';
wait_on_child_process = jobSwitches[QQJobSwitches::WAIT_ON_CHILD] == '1';

if (debug_on) {
    CERR << "START:  Waiting for a message..." << endl;
}
while ((new_sock = recvfd(worker_sd)) >= 0) {
    stringstream sstr;
    string ip_str, port_str;
    bool success;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...