面经

  • tcp 的四次挥手为什么需要 time_wait
    • 保证客户端发送的最后一个 ACK 报文可以到达服务端;
    • 防止已经失效的连接请求报文重新出现在本连接;
  • time_wait 多了怎么解决?
    • 客户端: 短连接太多,本地临时端口耗尽
      • 减少短连接,替换成长连接;
      • 让服务端主动关闭;
      • 扩大客户端可用端口资源 ip_local_port_range
      • 复用 timewait 对应的 socket,内核参数:net.ipv4.tcp_tw_reuse
      • 调整系统所能容纳的 timewait 数量,内核参数:net.ipv4.tcp_max_tw_buckets
    • 服务端: 短连接太多,服务端在主动关闭连接
      • 减少短连接,替换成长连接;
      • 让客户端主动关闭;
      • SO_REUSEADDR 帮助服务快速重启绑定;
  • 讲讲 TCP 长连接短连接 的区别?
    • 短连接: 一次请求/响应完成后,就关闭 TCP 连接。
    • 长连接: 建立一次 TCP 连接后,不立即关闭,而是复用这个连接传输多次数据。
  • TCP 长连接短连接 分别适用什么场景?
    • 短连接: 请求频率低、一次性事务型请求、对实时性要求不高的系统;
    • 长连接: 高频请求场景、实时通信场景;
  • 怎么判断一个 socket fd 已经关闭?
    • 判断本地 fd 是否已失效:fcntl(fd, F_GETFD)
    • 判断 对端连接 是否已经关闭:read 的返回值为零;
  • 知道 epoll 的边缘触发和水平触发?
    • 水平触发:只要 fd 关联的内核缓冲区还有数据没读完,epoll_wait 每次都会继续通知。
    • 边缘触发:只有 fd 关联的内核缓冲区从无到有,epoll_wait 只会通知一次。导致触发读事件后必须把数据收取干净,因为下一次不一定有机会再收取数据了
  • 怎么判断一个 socket fd 可读?(最常见的方法是看它是否触发了读事件)
  • UDP 使不使用 connect 的区别?
    • 发送时是否每次指定对端
      • 不使用 connect:每次 sendto 指定地址;
      • 使用 connect 后:可以直接 send
    • 接收时是否只收指定对端
      • 不使用 connect:谁发来的都可以收,recvfrom 能拿到来源地址;
      • 使用 connect 后:只接收这个 connect 绑定的那个对端的数据;
  • 知道 traceout
    • Traceroute 反复发送 IP 数据报,并将 TTL1 开始逐渐升高。每当路由器接收到 IP 报文以后则将 TTL1,当 TTL 减为 0 的时候路由器向源主机发送 ICMP 时间超过差错报告报文。
    • 当目的主机接收到 TTL 恰为 1 的数据报时 ,由于 IP 数据报封装的是无法交付的 UDP 用户数据报(故意使用一个非法的 UDP 端口),目标主机回向源主机发送 ICMP 终点不可达差错报告报文。接收到该报文后 Traceroute 发送终止。
    • 由此,使用 Traceroute 源主机就获取了到达目的主机所经过的所有路由器和相应的跳数,以此可建立网络的拓扑结构。整个过程相当于进行了一个广度优先搜索。
  • ICMP 的作用?
    • 为了更有效的转发 IP 数据报和提高交付成功的机会,ICMP 允许主机和路由器报告差错情况和提供有关异常情况的报告。
  • 知道 forkvforkclone 嘛?
    • fork()
      • 子进程和父进程有各自独立的进程地址空间,fork 后会重新申请一份资源,包括进程描述符、进程上下文、进程堆栈、内存信息、打开的文件描述符、进程优先级、根目录、资源限制、控制终端等,拷贝给子进程;
      • 为了减少工作量采用 写时拷贝 技术。子进程只复制父进程的页表,不会复制页面内容,页表的权限为 RD-ONLY。当子进程需要写入新内容时会触发 写时复制 机制,为子进程创建一个副本,并将页表权限修改为 RW
      • 由于需要修改页表,触发 page fault 等,因此 fork 需要 MMU 的支持;
    • vfork()
      • vfork 会将父进程除 mm_struct 的资源拷贝给子进程;
      • vfork 会阻塞父进程,直到子进程退出或释放虚拟内存资源,父进程才会继续执行;
      • 由于没有写时拷贝,不需要页表管理,因此 vfork 不需要 MMU
    • clone()
      • clone() 创建用户线程时,clone 不会申请新的资源,所有线程指向相同的资源;
      • 调用 pthread_create 时,linux 就会执行 clone,并通过不同的 clone_flags 标记;
  • 父进程通过 fork 创建一个子进程,怎么知道程序当前处于 父进程 还是 子进程
    • 通过 fork() 的返回值判断
      • 父进程 中,返回 子进程的 pid
      • 子进程 中,返回 0
    • 因为 fork() 之后,父子进程都会从 fork() 这一行继续往下执行。
  • 知道 tcp 网络编程的底层方法嘛?
    • 服务端: socketbindlistenacceptsendrecvclose
    • 客户端: socketbindconnect
  • MySQL 的覆盖索引?
    • 查询所需要的字段,全部都能从索引里直接拿到,不需要再 回表主键索引 或数据页里取数据。