我正在尝试用单独的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。据我了解,断管(EPIPE 32)通常是接收方问题,但是sendmail是本地进程...可能是因为我发送的数据太多而无法写入?还是我在pthread实例中做的不好?还是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))
}

最佳答案

EPIPE表示另一端(您正在写入的进程)已死亡。如果发生派生故障(发生popen调用 shell 程序,因此涉及另一个子进程),则可能发生这种情况,因为系统中临时有太多进程。更直接的原因是sendmail失败并在读取所有标准输入之前过早退出,例如由于电子邮件标题格式错误。

不幸的是,popen不是一个非常可靠的接口(interface)。您可以将fork / execveposix_spawn与一个用于输入的临时文件或使用poll进行I / O复用的更好,以便能够捕获sendmail可能产生的任何错误。或者,您可以尝试使用sendmail调用-oee,它应该通过电子邮件报告任何错误,但是如果sendmail本身创建失败,这将无济于事。

关于c++ - C++:从pthread调用sendmail会导致管道中断,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47316855/

10-11 22:36
查看更多