如何重现 Linux 中的接受错误
How to reproduce the accept error in Linux
我正在学习 Unix 网络编程第 1 卷,我想重现 Linux 中 RST 的接受错误。
- 服务器:调用
socket()
、bind()
、listen()
和 sleep(10)
- 客户端:调用
LINGER
、close()
和 return
的 socket()
、connect()
、setsockopt()
- 服务器:呼叫
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;
}
没有。我想你会得到一个空的但完整的连接(没有数据)。内核将管理完整的连接建立,然后它将立即获得一个 FIN 数据包(意思是 EOF,而不是重置)并将处理它(或等待用户 space 进程关闭它的一侧,将 FIN 发送到另一边)对于连接中止,您需要重新启动客户端计算机(或服务器),不允许它发送 FIN 数据包(或在 之前 重新启动它之前将其与网络断开连接)一个ACK 永远不会得到答复,因此您不会收到从 ACK 发送的 RST。
当双方之间存在某种状态不匹配时,内核会自动发送 RST 数据包。为了在正确的实现中发生这种情况,您必须强制这种状态不匹配(这就是为什么需要重启机器)
- 在双方之间建立连接并停止(休眠)以确保在断开电缆之前连接处于 ESTABLISHED 状态。
- 从网络上断开对等点之一的物理连接,因此您不允许其流量进入网络。
- 重启机器,所有socket都处于IDLE状态
- 重新连接电缆。一旦等待的机器从睡眠中醒来并再次开始发送数据包,它将从另一端收到一个 RST 段,因为它已经重新启动并且 TCP 不知道该连接。
获取 RST 段的其他方法涉及错误的 TCP 实现,或破坏传输中的数据包(更改传输中的发送方或接收方序列号)
RST 数据包的目的不是为 TCP 添加功能,而是检测不当行为,因为正确使用套接字应该无法获得重置。 Listen 系统调用允许您在内核 space 中保留资源,以允许用户 space 进程在客户端尝试连接时准备处理连接。如果你按照你的意图去做,你会得到一个没有数据的连接,但是有效的连接,SO_LINGER
是为了在机器没有时间互相发送数据包时强制丢失状态.. .但是正在连接,整个连接都在内核中处理,并且不会中止。
Linux accept() (and accept4()) passes already-pending network errors
on the new socket as an error code from accept(). This behavior
differs from other BSD socket implementations. For reliable
operation the application should detect the network errors defined
for the protocol after accept() and treat them like EAGAIN by
retrying. In the case of TCP/IP, these are ENETDOWN, EPROTO,
ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, and
ENETUNREACH.
我正在学习 Unix 网络编程第 1 卷,我想重现 Linux 中 RST 的接受错误。
- 服务器:调用
socket()
、bind()
、listen()
和sleep(10)
- 客户端:调用
LINGER
、close()
和return
的 - 服务器:呼叫
accept()
socket()
、connect()
、setsockopt()
我认为第 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;
}
没有。我想你会得到一个空的但完整的连接(没有数据)。内核将管理完整的连接建立,然后它将立即获得一个 FIN 数据包(意思是 EOF,而不是重置)并将处理它(或等待用户 space 进程关闭它的一侧,将 FIN 发送到另一边)对于连接中止,您需要重新启动客户端计算机(或服务器),不允许它发送 FIN 数据包(或在 之前 重新启动它之前将其与网络断开连接)一个ACK 永远不会得到答复,因此您不会收到从 ACK 发送的 RST。
当双方之间存在某种状态不匹配时,内核会自动发送 RST 数据包。为了在正确的实现中发生这种情况,您必须强制这种状态不匹配(这就是为什么需要重启机器)
- 在双方之间建立连接并停止(休眠)以确保在断开电缆之前连接处于 ESTABLISHED 状态。
- 从网络上断开对等点之一的物理连接,因此您不允许其流量进入网络。
- 重启机器,所有socket都处于IDLE状态
- 重新连接电缆。一旦等待的机器从睡眠中醒来并再次开始发送数据包,它将从另一端收到一个 RST 段,因为它已经重新启动并且 TCP 不知道该连接。
获取 RST 段的其他方法涉及错误的 TCP 实现,或破坏传输中的数据包(更改传输中的发送方或接收方序列号)
RST 数据包的目的不是为 TCP 添加功能,而是检测不当行为,因为正确使用套接字应该无法获得重置。 Listen 系统调用允许您在内核 space 中保留资源,以允许用户 space 进程在客户端尝试连接时准备处理连接。如果你按照你的意图去做,你会得到一个没有数据的连接,但是有效的连接,SO_LINGER
是为了在机器没有时间互相发送数据包时强制丢失状态.. .但是正在连接,整个连接都在内核中处理,并且不会中止。
Linux accept() (and accept4()) passes already-pending network errors on the new socket as an error code from accept(). This behavior differs from other BSD socket implementations. For reliable operation the application should detect the network errors defined for the protocol after accept() and treat them like EAGAIN by retrying. In the case of TCP/IP, these are ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, and ENETUNREACH.