本文源自于个人github仓库:https://github.com/forthespada/InterviewGuide
github仓库内有PDF版本下载方式,欢迎各位star、fork~
立志收录计算机校招、社招面试最全面试八股文,无内鬼来点八股文~

81、对于FIN_WAIT_2,CLOSE_WAIT状态和TIME_WAIT状态?你知道多少?

  • FIN_WAIT_2:

    • 半关闭状态。

    • 发送断开请求一方还有接收数据能力,但已经没有发送数据能力。

  • CLOSE_WAIT状态:

    • 被动关闭连接一方接收到FIN包会立即回应ACK包表示已接收到断开请求。

    • 被动关闭连接一方如果还有剩余数据要发送就会进入CLOSED_WAIT状态。

  • TIME_WAIT状态:

    • 又叫2MSL等待状态。

    • 如果客户端直接进入CLOSED状态,如果服务端没有接收到最后一次ACK包会在超时之后重新再发FIN包,此时因为客户端已经CLOSED,所以服务端就不会收到ACK而是收到RST。所以TIME_WAIT状态目的是防止最后一次握手数据没有到达对方而触发重传FIN准备的。

    • 在2MSL时间内,同一个socket不能再被使用,否则有可能会和旧连接数据混淆(如果新连接和旧连接的socket相同的话)。

82、你了解流量控制原理吗?

  • 目的是接收方通过TCP头窗口字段告知发送方本方可接收的最大数据量,用以解决发送速率过快导致接收方不能接收的问题。所以流量控制是点对点控制。

  • TCP是双工协议,双方可以同时通信,所以发送方接收方各自维护一个发送窗和接收窗。

    • 发送窗:用来限制发送方可以发送的数据大小,其中发送窗口的大小由接收端返回的TCP报文段中窗口字段来控制,接收方通过此字段告知发送方自己的缓冲(受系统、硬件等限制)大小。

    • 接收窗:用来标记可以接收的数据大小。

  • TCP是流数据,发送出去的数据流可以被分为以下四部分:已发送且被确认部分 | 已发送未被确认部分 | 未发送但可发送部分 | 不可发送部分,其中发送窗 = 已发送未确认部分 + 未发但可发送部分。接收到的数据流可分为:已接收 | 未接收但准备接收 | 未接收不准备接收。接收窗 = 未接收但准备接收部分。

  • 发送窗内数据只有当接收到接收端某段发送数据的ACK响应时才移动发送窗,左边缘紧贴刚被确认的数据。接收窗也只有接收到数据且最左侧连续时才移动接收窗口。

83、建立TCP服务器的各个系统调用过程是怎样的?

  • 服务器:

    • 创建socket -> int socket(int domain, int type, int protocol);

      • domain:协议域,决定了socket的地址类型,IPv4为AF_INET。

      • type:指定socket类型,SOCK_STREAM为TCP连接。

      • protocol:指定协议。IPPROTO_TCP表示TCP协议,为0时自动选择type默认协议。

    • 绑定socket和端口号 -> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

      • sockfd:socket返回的套接字描述符,类似于文件描述符fd。

      • addr:有个sockaddr类型数据的指针,指向的是被绑定结构变量。

          // IPv4的sockaddr地址结构
          struct sockaddr_in {
              sa_family_t sin_family;    // 协议类型,AF_INET
              in_port_t sin_port;    // 端口号
              struct in_addr sin_addr;    // IP地址
          };
          struct in_addr {
              uint32_t s_addr;
          }
      • addrlen:地址长度。
    • 监听端口号 -> int listen(int sockfd, int backlog);

      • sockfd:要监听的sock描述字。

      • backlog:socket可以排队的最大连接数。

    • 接收用户请求 -> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

      • sockfd:服务器socket描述字。

      • addr:指向地址结构指针。

      • addrlen:协议地址长度。

      • 注:一旦accept某个客户机请求成功将返回一个全新的描述符用于标识具体客户的TCP连接。

    • 从socket中读取字符 -> ssize_t read(int fd, void *buf, size_t count);

      • fd:连接描述字。

      • buf:缓冲区buf。

      • count:缓冲区长度。

      • 注:大于0表示读取的字节数,返回0表示文件读取结束,小于0表示发生错误。

    • 关闭socket -> int close(int fd);

      • fd:accept返回的连接描述字,每个连接有一个,生命周期为连接周期。

      • 注:sockfd是监听描述字,一个服务器只有一个,用于监听是否有连接;fd是连接描述字,用于每个连接的操作。

  • 客户机:

    • 创建socket