c - 如何在 Linux 中重现接受错误
问题描述
我正在学习 Unix Network Programming Volume 1,我想在 Linux 中重现 RST 的接受错误。
- 服务器:调用
socket()
,bind()
,listen()
, 和sleep(10)
- 客户:呼叫
socket()
,connect()
,setsockopt()
ofLINGER
,close()
和return
- 服务器:调用
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;
}
解决方案
没有。我想你会得到一个空的但完整的连接(没有数据)。内核将管理完整的连接建立,然后它会立即获得一个 FIN 数据包(意思是 EOF,而不是重置)并处理它(或等待用户空间进程关闭其一侧,将 FIN 发送到另一侧)对于连接中止,您需要重新启动客户端计算机(或服务器),但不允许它发送 FIN 数据包(或在重新启动之前将其与网络断开连接) 永远不会回答 ACK,因此您不会收到 RST来自 ACK。
当两方之间存在某种状态不匹配时,内核会自动发送 RST 数据包。为了在正确的实现中发生这种情况,您必须强制这种状态不匹配(这就是机器重启是必要的原因)
- 在双方之间建立连接并停止(睡眠)以确保连接处于 ESTABLISHED 状态,然后再断开电缆。
- 在物理上断开其中一个对等方与网络的连接,因此您不允许其流量进入网络。
- 重新启动机器,因此所有套接字都处于空闲状态。
- 重新连接电缆。一旦等待的机器脱离睡眠并再次开始发送数据包,它将收到来自另一端的 RST 段,因为它已重新启动并且 TCP 不知道该连接。
获取 RST 段的其他方法涉及 TCP 的错误实现,或在传输中破坏数据包(在传输中更改发送方或接收方序列号)
RST 数据包的目的不是为 TCP 添加功能,而是检测错误行为,因为正确使用套接字应该无法进行重置。Listen syscall 允许您在内核空间中保留资源,以允许用户空间进程在客户端尝试连接时准备处理连接。如果您按照您的意愿进行操作,您将获得一个没有数据但有效连接的连接,SO_LINGER
当机器没有时间相互发送数据包时是否会强制丢失状态......但是正在连接,整个连接都在内核中处理,并且不会中止。
推荐阅读
- objective-c - 如何用颜色填充 vImage 缓冲区 - Cocoa Objective C
- php - 根据分配的标签添加自定义类
- azure - 将 Azure 批处理集群设置为在特定时间运行
- python - Django 路由 - 空路径与这些中的任何一个都不匹配
- oracle - 是否有直接的方法将触发器重新定位到不同的表
- c# - 如何使用 C# 部署 Kubernetes yaml
- c++ - C++ 自定义范围类型 MSVC 可以编译,但 G++ 不能
- javascript - 如何删除 Highcharts 中单个图例的图例符号?
- javascript - 使用 localStorage 持久化数据 - React.js
- docker - 使用 ramdisk 更快地构建 Dockerfile