主要针对牛客的这个标准的 webserver 做总结,都是常见问题
1.主线程和线程池是怎么联系起来的
主线程和线程池的联系是通过任务队列的方式,当 epoll 事件通知时把对应的任务,连接送入工作队列中,然后线程池的线程的动作就是不断取,如果没有就阻塞。
2.定时器是怎么设计的
定时器使用(双向)升序链表,按照过期时间越往前的越在链表前面,这样可以一次处理。
在具体过程中向内核注册每五秒发送一个 alarm 信号,然后信号处理就是写一个字到一个套接字,然后主线程就检测到事件,对于这个事件主线程的处理就是遍历链表,剔除已经过期的的连接。
对于读写的情况要把定时器重新插入。
3.使用的垂直模式还是非垂直模式,为什么非阻塞,然后怎么去处理同一个套接字的多个请求?
垂直模式是对于同一个事件,如果没有读完,没有处理完成,epoll 会反复通知,而非垂直模式是如果不是发生了新的读写等,只通知一次。
对于为什么循环读取是要保证处理完整,使用非阻塞模式是避免线程池中的线程阻塞在这个套接字上,然后如果多个事件也不会反复通知,因为通过 epolloneSHOT 注册的只通知一次,后续处理完成再注册。
et 非阻塞模式读取完是通过读取到错误码 EAGAIN 来判断的。
4.如果想要提高并发连接的数量,怎么做
首先是套接字连接的限制,要调整端口数,文件描述符可以接受的数量、横向扩展,增加机器、提高线程数量、对于 IO 的主线程也使用多个。
5.对于写事件的注册?
对于发送大的文件,可能一次不能直接在缓冲区写完文件,因此要记录写到都文件的偏移量,然后用 epollout 注册写事件下次可以写的时候继续发送,直到发送完毕之后使用 mumap。
mmap 减少了从内核内存到用户内存的搬运,提高了效率。
总结:定时器的部分之前感觉不会被问到准备就不是很充分事实证明多准备是没有错的。