面试题答案
一键面试资源管理
- 文件描述符管理
- 打开文件描述符时记录:在打开网络套接字(如
socket()
函数调用)时,将返回的文件描述符记录在一个数组或链表中。
int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } // 假设fd_list是一个数组,fd_count是已使用的文件描述符数量 fd_list[fd_count++] = sockfd;
- 关闭文件描述符:在程序结束或不再需要某个连接时,遍历记录文件描述符的数组或链表,关闭每个文件描述符。
for (int i = 0; i < fd_count; i++) { close(fd_list[i]); }
- 打开文件描述符时记录:在打开网络套接字(如
- 动态内存管理
- 使用内存池:预先分配一块较大的内存,根据需要从这块内存中分配小块内存。当不再使用时,将小块内存归还到内存池,而不是直接释放给系统。
- 记录分配的内存:使用链表记录每次动态分配的内存地址。在释放内存时,遍历链表释放所有分配的内存。
void *ptr = malloc(size); if (ptr == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } // 假设mem_list是一个链表,将ptr添加到链表中 add_to_mem_list(ptr);
- 释放内存:在程序结束或不再需要内存时,遍历链表释放所有内存。
free_memory_list(mem_list);
故障处理机制
- 连接中断处理
- 心跳机制:在TCP连接中,定期发送心跳包(如简单的字节流)给对方。如果在一定时间内没有收到心跳响应,认为连接中断。
// 发送心跳包 int send_heartbeat(int sockfd) { char heartbeat_msg[] = "HEARTBEAT"; ssize_t bytes_sent = send(sockfd, heartbeat_msg, sizeof(heartbeat_msg), 0); if (bytes_sent < 0) { perror("send heartbeat failed"); return -1; } return 0; }
- 重新连接:当检测到连接中断时,尝试重新建立连接。
int reconnect(int sockfd, struct sockaddr_in servaddr) { close(sockfd); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket creation failed"); return -1; } if (connect(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { perror("connect failed"); close(sockfd); return -1; } return sockfd; }
- 丢包处理
- 确认机制:对于TCP,本身有确认机制。对于UDP,可以自己实现确认机制。发送数据时记录发送的数据包,接收方返回确认消息。如果在一定时间内没有收到确认消息,重发数据包。
// UDP发送数据并等待确认 int send_udp_data(int sockfd, struct sockaddr_in servaddr, const char *data, size_t len) { ssize_t bytes_sent = sendto(sockfd, data, len, MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr)); if (bytes_sent < 0) { perror("sendto failed"); return -1; } // 等待确认 char ack[ACK_SIZE]; struct sockaddr_in from; socklen_t fromlen = sizeof(from); fd_set read_fds; FD_ZERO(&read_fds); FD_SET(sockfd, &read_fds); struct timeval timeout; timeout.tv_sec = 1; // 等待1秒 timeout.tv_usec = 0; int activity = select(sockfd + 1, &read_fds, NULL, NULL, &timeout); if (activity < 0) { perror("select error"); return -1; } else if (activity > 0) { ssize_t bytes_recv = recvfrom(sockfd, ack, ACK_SIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen); if (bytes_recv < 0) { perror("recvfrom failed"); return -1; } // 检查确认消息 if (check_ack(ack)) { return 0; } } // 重发 return send_udp_data(sockfd, servaddr, data, len); }