如何在Linux中重现接受错误

时间:2018-11-13 08:13:51

标签: c linux operating-system unix-socket

我正在学习Unix网络编程第1卷,我想重现Linux中RST的接受错误。

  1. 服务器:呼叫socket()bind()listen()sleep(10)
  2. 客户端:呼叫socket()connect()setsockopt()中的LINGERclose()return
  3. 服务器:致电accept()

我认为第3步会出现类似ECONNABORTED的错误,但不会。

我想知道为什么吗?

如果您能帮助我,我将不胜感激。

以下是服务器code

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <strings.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    struct sockaddr_in addr;

    bzero(&addr, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(6666);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);

    bind(sock, (struct sockaddr*)(&addr), (socklen_t)(sizeof addr));
    listen(sock, 5);
    sleep(10);

    if (accept(sock, NULL, NULL) < 0)
        perror("error");
    else
        printf("right");

    return 0;
}

以下是客户端code

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <strings.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    struct sockaddr_in addr;

    bzero(&addr, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(6666);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);

    connect(sock, (struct sockaddr*)(&addr), (socklen_t)(sizeof addr));

    struct linger ling;
    ling.l_onoff = 1;
    ling.l_linger = 0;
    setsockopt(sock, SOL_SOCKET, SO_LINGER, &ling, sizeof ling);
    close(sock);

    return 0;
}

2 个答案:

答案 0 :(得分:2)

不。我认为您将获得一个空的但完整的连接(无数据)。内核将管理完整的连接建立,然后将立即获得FIN数据包(意味着EOF,而不是重置)并对其进行处理(或等待用户空间进程关闭其一侧,以将FIN发送到另一侧)对于连接中止,您需要在不允许客户端发送FIN数据包的情况下重新引导客户端计算机(或服务器)(或在重新引导计算机之前将其与网络断开连接)不会收到来自ACK的RST。

当两方之间存在某些状态不匹配时,内核会自动发送

RST数据包。为了使这种情况在正确的实现中发生,您必须强制这种状态不匹配(这就是为什么必须重新启动计算机的原因)

  • 在双方之间建立连接并停止连接(保持睡眠状态),以确保在断开电缆连接之前该连接处于ESTABLISHED状态。
  • 从网络上物理断开对等方之一,因此您不允许其流量进入网络。
  • 重新启动计算机,以便所有套接字都处于IDLE状态。
  • 重新连接电缆。一旦等待的机器退出睡眠状态并再次发送数据包,它就会从另一端收到RST段,因为它已经重新启动并且TCP不知道该连接。

获取RST段的其他方法包括TCP的错误实现或处理传输中的数据包(更改传输中的发送方或接收方序列号)

RST数据包的目的不是向TCP添加功能,而是检测错误行为,因此,没有任何方法可以通过正确使用套接字来进行重置。 Listen syscall可以让您在内核空间中保留资源,以允许用户空间进程准备在客户端尝试连接时处理连接。如果您执行了您打算的操作,那么将得到一个没有数据的连接,但有一个有效的连接,当机器没有时间互相发送数据包时,SO_LINGER会强制失去状态。 ...,但已连接,整个连接都在内核中处理,并且不会中止。

答案 1 :(得分:0)

  

Linux accept()(和accept4())传递已经挂起的网络错误          在新套接字上作为来自accept()的错误代码。这种行为          与其他BSD套接字实现不同。为了可靠          操作应用程序应该检测到定义的网络错误          for accept()之后的协议,并通过          重试。对于TCP / IP,它们是ENETDOWN,EPROTO,          ENOPROTOOPT,EHOSTDOWN,ENONET,EHOSTUNREACH,EOPNOTSUPP和          ENETUNREACH。

http://man7.org/linux/man-pages/man2/accept.2.html