面试题答案
一键面试1. 重传机制
在Linux C语言UDP通信中实现重传机制,一般步骤如下:
- 设置定时器:使用
setitimer
函数设置定时器,在指定时间后触发信号。例如:
#include <sys/time.h>
#include <signal.h>
#include <stdio.h>
void timeout_handler(int signum) {
// 重传逻辑
printf("Timeout, retransmit data...\n");
}
int main() {
struct itimerval timer;
struct sigaction sa;
// 初始化信号处理函数
sa.sa_handler = timeout_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL);
// 设置定时器
timer.it_value.tv_sec = 1; // 首次触发时间1秒
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 0; // 不重复触发
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
// 其他UDP通信代码
//...
return 0;
}
- 记录发送时间:在发送数据时记录当前时间戳。可以定义一个结构体来存储数据和发送时间:
typedef struct {
char data[1024];
struct timeval send_time;
} Packet;
- 重传逻辑:在定时器触发的信号处理函数中,检查是否有未确认的数据,并进行重传。例如:
Packet packets[10];
int packet_count = 0;
void timeout_handler(int signum) {
for (int i = 0; i < packet_count; i++) {
struct timeval now;
gettimeofday(&now, NULL);
long elapsed_time = (now.tv_sec - packets[i].send_time.tv_sec) * 1000000 + (now.tv_usec - packets[i].send_time.tv_usec);
if (elapsed_time > 1000000) { // 假设1秒未确认则重传
// 重传packets[i].data
printf("Retransmitting packet: %s\n", packets[i].data);
}
}
}
2. 处理数据包顺序
- 给数据包编号:在发送端,为每个数据包分配一个唯一的编号。可以在数据包结构体中添加一个编号字段:
typedef struct {
int seq_num;
char data[1024];
struct timeval send_time;
} Packet;
发送时递增编号:
int seq_num = 0;
Packet packet;
packet.seq_num = seq_num++;
// 填充数据并发送
- 接收端处理:接收端维护一个缓冲区,根据数据包编号将数据包按顺序排列。例如:
#define MAX_SEQ 100
Packet received_packets[MAX_SEQ];
int received_flags[MAX_SEQ] = {0};
void process_packet(Packet packet) {
if (packet.seq_num >= 0 && packet.seq_num < MAX_SEQ) {
received_packets[packet.seq_num] = packet;
received_flags[packet.seq_num] = 1;
// 检查是否有连续的数据包可以处理
for (int i = 0; i < MAX_SEQ; i++) {
if (!received_flags[i]) {
break;
}
// 处理received_packets[i].data
printf("Processing packet: %s\n", received_packets[i].data);
received_flags[i] = 0;
// 移动后续数据包
for (int j = i + 1; j < MAX_SEQ; j++) {
received_packets[j - 1] = received_packets[j];
received_flags[j - 1] = received_flags[j];
}
}
}
}
3. 确认机制
- 发送确认包:接收端接收到数据包后,向发送端发送确认包(ACK)。确认包可以只包含被确认数据包的编号。
- 发送端处理确认包:发送端接收到确认包后,标记对应的数据包已被确认,不再进行重传。例如,可以在发送端维护一个确认标志数组:
int ack_flags[MAX_SEQ] = {0};
// 接收到ACK包处理函数
void handle_ack(int seq_num) {
if (seq_num >= 0 && seq_num < MAX_SEQ) {
ack_flags[seq_num] = 1;
}
}
在重传逻辑中,只重传未被确认的数据包:
void timeout_handler(int signum) {
for (int i = 0; i < packet_count; i++) {
if (!ack_flags[packets[i].seq_num]) {
// 重传packets[i].data
printf("Retransmitting packet: %s\n", packets[i].data);
}
}
}