Unix网络编程里面的5种IO分类
-
阻塞IO
-
非阻塞IO
-
信号驱动IO
-
IO复用模型
-
异步IO
前四种都是同步IO,最后一种是异步的。(信号驱动IO因为数据从内核空间复制到用户空间的时候仍然会被阻塞,因此算也是同步的)。
-
同步IO——导致请求进程阻塞(请求进程:调用IO API的那个进程)
-
异步IO——不会导致请求进程阻塞
select等待某个事件的发生,或是新连接的建立,或是已有连接的数据、FIN或RST。
一般模型如下:https://www.cnblogs.com/zhchy89/p/8850048.html
初始化 (socket,bind,listen);
while(1)
{
设置监听读写文件描述符 (FD_SET*);
调用 select;
如果是倾听套接字就绪 , 说明一个新的连接请求建立
{
建立连接 (accept);
将accept返回的client fd加入到监听文件描述符中去 ;
}
否则说明是一个已经连接过的描述符
{
进行操作 (read 或者 write);
}
}
select、poll、epoll的区别(忘了在哪篇博客上看的了)
-
select函数在响应时,并不知道是哪个socket状态改变了,因此需要遍历列表,时间复杂度O(n),而且有连接上限(32位机1024,64位机2048);
-
poll和select一样,也需要遍历列表(O(n)),但是对连接上限作出了改进,无连接上限(因为内部采用了链表实现)
-
epoll对以上的缺点作出了改善,epoll是事件响应机制(event poll),在fd中,有指向响应函数的指针,因此时间复杂度只有O(1)。
-
除此之外, select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,而epoll只要一次拷贝( 每次注册新的监听事件到epoll句柄中时)。
TCP
-
面向连接
-
面向字节流
-
可靠性——当TCP向一端发送数据时,要求收到确认,如果没有收到确认,就会重传数据,并等待更长的时间。如果多次重传失败,才放弃重传。
-
含有估算传输往返时间(RTT)的算法
-
序列号。具有排序功能,保证数据按顺序到达,保证一份数据只会到达一次,不会在网络中多次复制后多次到达。
-
流量控制——确保发送端发送的数据不会过于频繁,超过接收端的接收能力。通过通告窗口控制。
-
拥塞控制
-
是全双工的
PS:
【1】三次握手、四次挥手补充:
-
挥手时的第一个FIN可以和最后发送 大数据一起发送(某些情况下)。
-
TIME_WAIT状态(主动断开方的最后一个状态)
时长:2MSL(IP数据表能在网络中存活的最长时间MSL的两倍),一般为2min或4min
存在的理由:为了把原来的连接里面的重复数据包都已经在网络中消逝。避免老的连接的数据影响新建立的连接(新老连接的IP和端口号相同,新的被称为老的连接到化身)。
-
如果服务器主机崩溃后不主动给客户端发消息,那么客户端不知道服务端的主机已经崩溃了
【2】拥塞控制通过UDP实现
UDP
-
面向无连接(《Unix网络编程》8.11节中提到可以给UDP调用connect,但与TCP含义不同,是指这个UDP只能从特定的服务器端口(用户通过connect指定)收发数据,来自其他服务器的数据包将会被丢弃)
-
面向数据报
-
是全双工的
-
与TCP相比,UDP不具备可靠性(不知道是否丢失、不会主动重传)、不具备排序能力、不具备流量控制的能力。
PS:
【1】其实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。
【2】UDP比起TCP避免了很多链接建立和终止链接所需要的开销。
【3】UDP编写的常见应用程序有:DNS、NFS、SNMP等
【4】由于UDP数据丢失,接收端可能会一直阻塞在等待数据返回的read上,一般的解决方案是设定超时时间。
其他:
【1】SCTP协议
-
流控制传输协议
-
与TCP和UDP并列
-
全双工。能像TCP一样提供可靠性、排序、流量控制,能像UDP一样,面向消息。
-
2000年提出,相对年轻,因此知名度没有那么广
【2】TCP中的RST包与RST攻击
RST包——RST表示复位,用来异常的关闭连接。(就像上面说的一样,发送RST包关闭连接时,不必等缓冲区的包都发出去(不像上面的FIN包),直接就丢弃缓存区的包发送RST包。而接收端收到RST包后,也不必发送ACK包来确认。TCP处理程序会在自己认为的异常时刻发送RST包。例如,A向B发起连接,但B之上并未监听相应的端口,这时B操作系统上的TCP处理程序会发RST包。)
RST攻击是指第三方伪造A或者B发送RST包或者SYN包(然接收方以为发送发异常主动强制关闭连接)
【3】拒绝服务型攻击
客户端给服务端发了个字节(不是EOF)之后就挂起了,服务端必须不断等待读取下一个字节。
解决方案:(1)使用非阻塞式IO;(2)开多线程;(3)对IO操作设置超时时间
其他参考资料:https://www.cnblogs.com/zhchy89/p/8850048.html