C++:从 pthread 调用 sendmail 导致 Broken Pipe

标签 c++ pthreads sendmail popen broken-pipe

我正在尝试在单独的 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。根据我的阅读,Broken Pipe (EPIPE 32) 通常是接收器问题,但 sendmail 是本地进程......可能是我向 fwrite 发送了太多数据?或者我在我的 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 表示另一端(您正在写入的进程)已经死亡。如果存在 fork 失败(popen 调用 shell,因此涉及另一个子进程)可能会发生这种情况,因为系统中暂时有太多进程。更直接的原因是 sendmail 在读取所有标准输入之前失败并过早退出,例如由于格式错误的电子邮件标题。

不幸的是,

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

关于C++:从 pthread 调用 sendmail 导致 Broken Pipe,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47316855/

相关文章:

c++ - 在 Rcpp Makevars 中设置 CXXFLAGS

c++ - 多级继承中拷贝构造函数的调用顺序是怎样的?

c++ - 如何通过循环将 OpenMP 线程拆分为子团队

c++ - 为什么在 32 位 x86 架构上默认对齐 `int64_t` 8 字节?

linux - sched_getcpu() 在 Linux 上可靠吗?

python - 在 Django 中处理联系表,未发送电子邮件

c - 在 C 中没有锁的线程之间共享 bool 值

c - 是否可以确定持有互斥锁的线程?

plsql - APEX_MAIL.SEND 函数不起作用,但它没有给出任何错误

objective-c - 如何使用 objective C/cocoa 以编程方式发送电子邮件