send() 总是被 EPIPE 中断

Man*_*edo 4 c linux

我在 GNU/Linux 下用 C 编程的多线程服务器中有这种奇怪的行为。在发送数据时,最终会被 SIGPIPE 中断。我设法忽略了 send() 中的信号,并因此在每次操作后处理 errno。

因此,它有两种单独的发送方法,一种一次性发送大量数据(或至少尝试发送),另一种发送几乎相似的数据并将其切成小块。最后,我尝试用它来保持它发送数据。

do
{
    total_bytes_sent += send(client_sd, output_buf + total_bytes_sent,
                             output_buf_len - total_bytes_sent, MSG_NOSIGNAL);
}
while ((total_bytes_sent < output_buf_len) && (errno != EPIPE));
Run Code Online (Sandbox Code Playgroud)

这段丑陋的代码在某些情况下可以发挥作用,但并非总是如此。

我很确定这不是硬件或 ISP 问题,因为这台服务器在六台欧洲服务器上运行,四台在德国,两台在法国。

有任何想法吗?

提前致谢。

编辑 1:是的,我注意到这段代码很糟糕(感谢 Jay)。我最初的意思是,无论客户端是否切断通信,这段代码都会给我一个 EPIPE。

编辑 2:我尝试了一个 send() 并且它随机给了我同样的错误。这很奇怪,因为我无法发送大数据块。我尝试扩大发送缓冲区,但没有奏效。

编辑 3:根据要求,这是一个更大的代码段。

data_buf_len = cur_stream->iframe_offset[cur_stream->iframe_num - 1] - first_offset;
data_buf = cur_stream->data;
output_buf = compose_reply(send_params, data_buf, data_buf_len, &output_buf_len);

/* Obviously, time measuring is *highly* unaccurate, only for
 * design consistency purposes (it should return something).
 * */
clock_gettime(CLOCK_REALTIME, &start_time);
total_bytes_sent = send(client_sd, output_buf, output_buf_len, MSG_NOSIGNAL);
clock_gettime(CLOCK_REALTIME, &stop_time);
spent_time = (((int64_t)stop_time.tv_sec * NANOSEC_IN_SEC) +
    (int64_t)stop_time.tv_nsec) - (((int64_t)start_time.tv_sec * NANOSEC_IN_SEC) +
    (int64_t)start_time.tv_nsec);

free(output_buf);
unload_video(cur_video);

if (total_bytes_sent < 0)
{
    log_message(MESSAGE, __func__, IMSG_VIDEOSTOP, cur_video->path);
    log_message(MESSAGE, __func__, IMSG_VIDEOSTOP, NULL);   
}

/* Hope it will not serve >2147483647 seconds (~68 years) of video... */
return ((int)spent_time);
Run Code Online (Sandbox Code Playgroud)

只有一个带有大缓冲区的 send() 调用。还有另一个例子,太大而不能放在这里,它将每个缓冲区划分为更小的块,并为每个块调用 send()。

Jay*_*Jay 5

正如 EJP 已经建议的那样,如果另一侧关闭了套接字,则 EPIPE 会出现。另外,我不认为您将任何发送函数返回的添加到“total_bytes_sent”的逻辑是正确的,因为在某些情况下,发送可能会返回 -1,您仍然可以继续操作(例如:在非阻塞套接字的情况下,您可能会在需要重试的地方得到 errno EAGAIN)。

另外,如果 send 返回 0 并且 errno 不是 EPIPE,那么我猜你会不断循环。

编辑:您还可以检查是否在套接字上调用了关闭。即使那样也会导致这种行为。