面试题答案
一键面试处理网络拥塞
- 代码设计:
- 使用拥塞控制算法:在TCP协议栈中,Linux已经实现了多种拥塞控制算法,如CUBIC、reno等。应用层可以通过setsockopt函数设置TCP拥塞控制算法。
- 调整发送窗口:TCP拥塞控制的核心是动态调整发送窗口大小。发送方根据网络反馈(如ACK包的到达情况)来判断网络是否拥塞,进而调整发送窗口。
- 代码实现:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> int main() { int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } // 设置TCP拥塞控制算法为CUBIC const char* cubit = "cubic"; if (setsockopt(sockfd, IPPROTO_TCP, TCP_CONGESTION, cubit, strlen(cubit)) < 0) { perror("setsockopt for TCP_CONGESTION failed"); close(sockfd); exit(EXIT_FAILURE); } // 后续连接服务器等代码... close(sockfd); return 0; }
处理连接超时
- 代码设计:
- 设置socket选项:使用setsockopt函数设置SO_SNDTIMEO和SO_RCVTIMEO选项,分别控制发送和接收操作的超时时间。
- 使用select或epoll:在等待连接建立时,可以使用select或epoll机制来设置等待的超时时间。
- 代码实现:
- 使用setsockopt设置超时:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> int main() { int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } struct timeval timeout; timeout.tv_sec = 5; // 设置5秒超时 timeout.tv_usec = 0; if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout)) < 0) { perror("setsockopt for SO_SNDTIMEO failed"); close(sockfd); exit(EXIT_FAILURE); } if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)) < 0) { perror("setsockopt for SO_RCVTIMEO failed"); close(sockfd); exit(EXIT_FAILURE); } struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8080); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { perror("connect failed"); close(sockfd); exit(EXIT_FAILURE); } // 后续通信代码... close(sockfd); return 0; }
- 使用select设置连接超时:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/select.h> int main() { int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8080); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); fd_set fds; FD_ZERO(&fds); FD_SET(sockfd, &fds); struct timeval timeout; timeout.tv_sec = 5; timeout.tv_usec = 0; int ret = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); if (ret < 0 && errno == EINPROGRESS) { ret = select(sockfd + 1, NULL, &fds, NULL, &timeout); if (ret == 1) { int so_error; socklen_t len = sizeof(so_error); if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len) == 0 && so_error == 0) { // 连接成功 // 后续通信代码... } else { perror("connect error after select"); } } else { perror("select timeout"); } } else if (ret < 0) { perror("connect failed"); } close(sockfd); return 0; }
处理重连机制
- 代码设计:
- 记录连接状态:在客户端程序中,需要一个变量来记录当前的连接状态,如是否连接成功。
- 设置重连策略:可以设置固定时间间隔重连,也可以采用指数退避策略,即每次重连的时间间隔逐渐增大。
- 代码实现:
- 固定时间间隔重连:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> int main() { int sockfd; int connected = 0; struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8080); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); while (!connected) { sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket creation failed"); sleep(5); // 等待5秒后重连 continue; } if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) { connected = 1; } else { perror("connect failed"); close(sockfd); sleep(5); // 等待5秒后重连 } } // 连接成功后的通信代码... close(sockfd); return 0; }
- 指数退避重连:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> int main() { int sockfd; int connected = 0; struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8080); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); int retry_time = 1; while (!connected) { sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket creation failed"); sleep(retry_time); retry_time *= 2; continue; } if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) { connected = 1; } else { perror("connect failed"); close(sockfd); sleep(retry_time); retry_time *= 2; } } // 连接成功后的通信代码... close(sockfd); return 0; }