IO和网络IO
0、前言与基础知识
首先,网络io是一个基础设施,用于发送指定数据,至于什么数据(文字,视频,语言),业务逻辑和业务功能,不是网络io和C++所考虑的;;
在linux中,io就是fd 就是一个文件。
开发环境:

1、一个TCP连接示例
使用socket进行TCP/UDP的连接流程:

服务器的TCP状态机变化::
listen(sockfd, 5) 已完成三次握手但尚未被 accept() 取走的连接队列backlog的最大长度。
对于超出队列的新连接请求,它们会被忽略或拒绝 客户端收到ECONREFUSED 或超时
服务器状态机,socket建立 bind()阶段:阶段CLOSED ;; listen(进入侦听) LISTEN,开始处理三次握手;; 握手阶段 SYN_RECVD ; 对于完成握手的通过accept()进行ESTABLISHED
具体操作示例包括如下:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(port+i); // 8888 8889 8890 8891 .... 8987
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
perror("bind");
return 2;
}
if (listen(sockfd, 5) < 0) {
perror("listen");
return 3;
}
int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
如果代码执行到listen,可以在终端测试,指定端口是否在监测:
netstat -anpo | grep 8080
注意区分两个概念,, io和TCP连接, 在listen后的 客户端可以尝试连接服务器,完成握手,在客户端的终端测试中,可以看到一个条目,展示了这TCP连接,但此时不能通数据,应为没有通过accept()分配一个真正的IO(所谓的clientfd).如图,上一个连接对应最开始的sockfd;后者对应clientfd ;

这体现了tcp连接信息和fd的一对一连接关系;;
测试的神奇现象:
1、为了实现服务器连接多个客户端,我们将循环accept(),采用线程一对一进行处理对指定客户端clientfd的回复;;
在这个过程,发现文件描述符永远从3开始增加,因为Linux 系统中,每个进程启动时默认打开三个标准的文件描述符,编号分别为 0、1、2;分别表示标准输入(键盘)、标准输出(屏幕)、标准错误(屏幕)
2、通过netassist 我们创建3个客户端连接服务器,对应文件4 5 6;(3 是服务器fd) 当我们断开4, 再次连接 连接的是7;;但是等一段时间再连接就又连接 4 。这其中包含了一个TIME_WAIT状态,在主动关闭连接的一方发送最后一个ACK进入该状态,持续2MSL=60s; 它确保最后一个 ACK 能可靠到达对端,此时虽然进程close了fd,但是内核仍然在使用。
可以# 允许将 TIME_WAIT 状态的 socket 用于新的出站连接
sysctl -w net.ipv4.tcp_tw_reuse=1
3、fd = 4 不见了??

pidof 进程名 查找对应PID
每个进程都有一个 /proc/
# 查看进程 PID=1234 的所有文件描述符
ls -l /proc/1234/fd/
# 只查看某个特定的 fd(比如 fd=5)
ls -l /proc/1234/fd/5

fd = 4 确实代表了 epoll 实例的文件描述符
我使用了epoll 实例;;问题解决

浙公网安备 33010602011771号