C++:从 pthread 调用 sendmail 会导致管道中断

C++: Calling sendmail from pthread results in Broken Pipe

本文关键字:管道 中断 sendmail pthread 调用 C++      更新时间:2023-10-16

我正在尝试在单独的pthread中发送一封包含sendmail的电子邮件。 此代码在 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是一个本地进程......可能是我发送的数据太多而无法写入吗? 或者我在线程实例化中做了什么坏事? 还是发送邮件崩溃了?

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不是一个非常可靠的界面。 您可能最好使用 fork/execveposix_spawn ,无论是输入的临时文件还是使用 poll 的 I/O 多路复用,只是为了能够捕获sendmail可能产生的任何错误。 或者,您可以尝试使用 -oee 调用sendmail,它应该通过电子邮件报告任何错误,但如果sendmail本身的创建失败,这将无济于事。