C ++: вызов sendmail из результатов pthread в Broken Pipe

Я пытаюсь отправить электронное письмо с sendmail в отдельном pthread, Этот код работает 99,9% времени.

void* emailClientThreadFct(void* emailClientPtr)
{
EmailClient* emailClient = static_cast<EmailClient*>(emailClientPtr);

try
{
emailClient->Send();
}
catch (const exception& excep)
{
SYSLOG_ERROR("E-mail client exception: %s", excep.what());
}

delete emailClient;
return NULL;
}

// Send email for current output in a separate thread
pthread_t emailThread;
pthread_attr_t attr;

/* Initialize and set thread detached attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

pthread_create(&emailThread, &attr, emailClientThreadFct, emailClientObj);

0.1% времени я получаю ошибку fwrite error Broken Pipe когда я делаю следующий звонок. Из того, что я прочитал, Broken Pipe (EPIPE 32) обычно является проблемой приемника, но sendmail — это локальный процесс … Может ли быть так, что я отправляю слишком много данных в fwrite? Или что я делаю что-то плохое в своей инстанции? Или sendmail потерпел крах?

void EmailClient::Send() const
{
// Flush all open output streams, as recommended by popen man page
fflush(NULL);

string popen_command = "sendmail -t -oi >/dev/null 2>&1");

// Open pipe to Mail Transport Agent (MTA)
errno = 0;
FILE* stream = popen(popen_command.c_str(), "w");

if (stream == NULL)
{
throw exception("Cannot send email popen");
}
errno = 0;
if (fwrite(message.data(), message.size(), 1, stream) < 1)
{
pclose(stream);
throw exception("fwrite error ", strerror(errno));
}

// Close MTA
errno = 0;
if (pclose(stream) == -1)
printf("\"Error closing the MTA pipe (%s)\"", strerror(errno))
}

2

Решение

EPIPE означает, что другой конец (процесс, в который вы пишете) умер. Это может произойти в случае отказа вилки (popen вызывает оболочку, поэтому задействован еще один подпроцесс), поскольку в системе временно слишком много процессов. Более прямой причиной будет sendmail преждевременный сбой и выход из системы, прежде чем читать все стандартные входные данные, скажем, из-за искаженных заголовков электронной почты.

popen к сожалению не очень надежный интерфейс. Вы могли бы быть лучше, используя fork/execve или же posix_spawnлибо с временным файлом для ввода, либо с мультиплексированием ввода / вывода с использованием pollпросто чтобы иметь возможность зафиксировать любую ошибку, которая sendmail может генерировать. Кроме того, вы можете попробовать позвонить sendmail с -oee, который должен сообщать о любых ошибках по электронной почте, но это не поможет, если создание sendmail само по себе не получается.

0

Другие решения

Других решений пока нет …