网络
DNS解析过程
- 浏览器输入域名http://www.baidu.com ,操作系统会先检查hosts文件是否有这个网址的映射关系,如果有,就先调用这个IP,完成域名解析
- 如果hosts里面没有,则查找本地DNS解析器缓存,是否有这个网址的映射关系,如果有,就先调用这个IP,完成域名解析
- 如果还是没有,则会查找TCP/IP参数中设置的首选DNS服务器,此服务器收到查询时,如果要查询的域名,包含在本地配置的区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性
- 如果要查询的域名不由本地DNS服务器区域解析,但该服务器已经缓存了此网址映射关系,则调用这个IP地址映射,此解析不具有权威性
- 如果本地DNS服务器区域解析与缓存都失效,则根据本地服务器的设置(是否设置转发器)进行查询,如果未用转发器模式,本地DNS就把请求发送给13台根DNS,根DNS收到请求后会判断这个域名(.com)是谁来授权管理,并返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP后,将会请求这台服务器,如果这台服务器自己无法解析,它就会找一个管理.com域名的下一级DNS服务器地址(http://baidu.com)给本地DNS服务器。当本地服务器收到地址后,就会找http://baidu.com域服务器,重复上面的动作,进行查询,知道找到www.baidu.com的主机
- 如果用的是转发模式,此DNS服务器就会把请求转发给上一级服务器,由上一级服务器进行解析,上一级服务器如果不能解析,或找根DNS或把请求转发给上上级,以此循环。不管本地DNS服务器用的是转发,还是根提示,最后都是把结果返回给本地DNS服务器,再由本地DNS服务器返回给客户机。
请求过程用的是UDP还是TCP?
UDP,UDP发送快
为什么是13台根服务器?
为了做Prime Query
查Root Servers
性价比达到最高,肯定是一个包能放多少东西就塞多少东西,所以把所有Root Servers
的结果都塞进去,刚好能塞14个,不全用就塞13个吧,留下一点东西以备后患,留待扩展。
I/O
同步、异步:消息通信机制
阻塞,非阻塞:等待状态
五种I/O模型:
- 阻塞I/O
- 非阻塞I/O
- I/O多路复用
- 信号驱动I/O
- 异步I/O
select函数
多路复用I/O
1 | int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout); |
机制
select提供一个fd_set数据结构,实际上是一个long型的数组,里面的每个元素都与能打开的文件句柄建立联系,当调用select时,由内核根据IO状态修改fd_set的内容,由此通知select()的进程某个socket或文件可读
优点
一个线程处理多个I/O请求
问题
- 每次调用select时,都要把fd_set集合 从用户态拷贝到内核态,开销大
- 每次调用select时,都要遍历一遍fd_set集合,时间长
- 为了减少数据拷贝带来的性能损耗,fd_set的集合大小有限制,限制为1024(不可改变)
poll函数
1 | int poll(struct pollfd *fds, nfds_t nfds, int timeout); |
与select类似,但是没有大小限制
epoll函数
事件驱动I/O
1 | // 创建一个epoll句柄,size代表描述符数量,成功时返回epoll句柄描述符,失败时返回-1 |
epoll没有描述符个数限制,使用一个文件描述符管理多个描述符,将用户关心的文件描述符的事件存放到内核的一个事件表中,这样用户态和内核态的空间拷贝只需一次
触发方式:
- 水平触发(LT):默认,当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序可以不立即处理;下次调用epoll_wait时,会再次通知该事件(1->1)
- 边缘触发(ET):当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序必须处理该事件;如果不处理,下次调用epoll_wait时,不会通知该事件。(直到其他操作导致该描述符变为未就绪状态时,也就是边缘触发只在状态从未就绪到就绪通知一次)(0->1)