【问题标题】:How to catch a "connection reset by peer" error in C socket?如何在 C 套接字中捕获“对等连接重置”错误?
【发布时间】:2014-09-15 00:26:27
【问题描述】:

我有一个 C++ 和 Qt 应用程序,其中一部分实现了 C 套接字客户端。前段时间应用程序崩溃了,因为服务器发生了一些事情;我从那次崩溃中得到的唯一东西是 Qt Creator 的应用程序输出中的一条消息,说明

recv_from_client:对等方重置连接

我在网上对这个“对等连接重置”错误进行了一些研究,虽然 SO 和其他地方的一些线程确实设法解释了发生了什么,但没有一个告诉如何处理它 - 也就是说,我怎样才能“捕获”错误并继续我的应用程序而不会崩溃(特别是我从服务器读取的方法是在一个while循环内,所以我想停止while循环并进入我的代码的另一个地方将尝试重新建立连接)。

那么我怎样才能捕捉到这个错误来适当地处理它呢?不要忘记我的代码实际上是带有 Qt 的 C++ - C 部分是一个调用套接字方法的库。

编辑

顺便说一句,导致崩溃的可能方法(鉴于上述错误消息的“recv_from_client”部分)是:

int hal_socket_read_from_client(socket_t *obj, u_int8_t *buffer, int size)
{
    struct s_socket_private * const socket_obj = (struct s_socket_private *)obj;
    int retval = recv(socket_obj->client_fd, buffer, size, MSG_DONTWAIT); //last = 0

    if (retval < 0)
        perror("recv_from_client");

    return retval;
}

注意:我不确定在发生此错误时,recv 配置是使用 MSG_DONTWAIT 还是使用 0

【问题讨论】:

  • 如果socket方法返回错误,你的代码当前会做什么?
  • 当你说“crash”时,你的意思是抛出异常吗?如果是这样,那么只需在失败的方法周围使用 try/catch 块。
  • @DavidSchwartz 如果其中一个套接字方法返回错误,则会在应用程序控制台(使用 QDebug)中写入一条消息,并且(至少在这种情况下)软件应该继续运行。
  • 错误在于调用hal_socket_read_from_client的代码。输出显示perror 代码已执行,因此函数返回小于零的值。显然,调用代码爆炸了。所以问题出在调用这个函数的任何地方。
  • 另外,您的hal_socket_read_from_client 功能基本上无法使用。如果您要将MSG_DONTWAIT 传递给它,但您只在错误时返回-1,那么调用者如何判断错误是致命的还是非致命的?

标签: c++ c sockets recv


【解决方案1】:

read() 返回否定结果时,只需检查errno

通常不涉及崩溃。

while (...) {
    ssize_t amt = read(sock, buf, size);
    if (amt > 0) {
        // success
    } else if (amt == 0) {
        // remote shutdown (EOF)
    } else {
        // error

        // Interrupted by signal, try again
        if (errno == EINTR)
            continue;

        // This is fatal... you have to close the socket and reconnect
        // handle errno == ECONNRESET here

        // If you use non-blocking sockets, you also have to handle
        // EWOULDBLOCK / EAGAIN here

        return;
    }
}

【讨论】:

  • 只有EINTREAGAINEWOULDBLOCK是非致命的,recv()可以重试。其他任何事情都应该被视为致命错误,因此假设连接丢失。不要挑出ECONNRESET,因为可能会出现其他错误。
【解决方案2】:

这不是例外或信号。你不能抓住它。相反,您会收到一条错误消息,告诉您在尝试使用该套接字时连接已被重置。

int rc = recv(fd, ..., ..., ..., ...);

if (rc == -1)
{ 
  if (errno == ECONNRESET)
    /* handle it; there isn't much to do, though.*/
  else
     perror("Error while reading");
}

正如我所写,您无能为力。如果您正在使用一些 I/O 多路复用器,您可能希望从进一步的监控中删除该文件描述符。

【讨论】:

    猜你喜欢
    • 2014-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    • 2016-04-12
    相关资源
    最近更新 更多