首页 > 解决方案 > 如何在 Linux 中重现接受错误

问题描述

我正在学习 Unix Network Programming Volume 1,我想在 Linux 中重现 RST 的接受错误。

  1. 服务器:调用socket(), bind(), listen(), 和sleep(10)
  2. 客户:呼叫socket(), connect(), setsockopt()of LINGER,close()return
  3. 服务器:调用accept()

我认为第三步会出现类似的错误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;
}

标签: clinuxoperating-systemunix-socket

解决方案


没有。我想你会得到一个空的但完整的连接(没有数据)。内核将管理完整的连接建立,然后它会立即获得一个 FIN 数据包(意思是 EOF,而不是重置)并处理它(或等待用户空间进程关闭其一侧,将 FIN 发送到另一侧)对于连接中止,您需要重新启动客户端计算机(或服务器),但不允许它发送 FIN 数据包(或在重新启动之前将其与网络断开连接) 永远不会回答 ACK,因此您不会收到 RST来自 ACK。

当两方之间存在某种状态不匹配时,内核会自动发送 RST 数据包。为了在正确的实现中发生这种情况,您必须强制这种状态不匹配(这就是机器重启是必要的原因)

  • 在双方之间建立连接并停止(睡眠)以确保连接处于 ESTABLISHED 状态,然后再断开电缆。
  • 在物理上断开其中一个对等方与网络的连接,因此您不允许其流量进入网络。
  • 重新启动机器,因此所有套接字都处于空闲状态。
  • 重新连接电缆。一旦等待的机器脱离睡眠并再次开始发送数据包,它将收到来自另一端的 RST 段,因为它已重新启动并且 TCP 不知道该连接。

获取 RST 段的其他方法涉及 TCP 的错误实现,或在传输中破坏数据包(在传输中更改发送方或接收方序列号)

RST 数据包的目的不是为 TCP 添加功能,而是检测错误行为,因为正确使用套接字应该无法进行重置。Listen syscall 允许您在内核空间中保留资源,以允许用户空间进程在客户端尝试连接时准备处理连接。如果您按照您的意愿进行操作,您将获得一个没有数据但有效连接的连接,SO_LINGER当机器没有时间相互发送数据包时是否会强制丢失状态......但是正在连接,整个连接都在内核中处理,并且不会中止。


推荐阅读