基于UDP Socket的C语言视频传输代码校验和添加后执行异常
UDP视频传输校验和添加后服务端卡死问题排查修复
问题描述
基于C语言UDP Socket实现的视频传输代码,原传输功能正常。添加校验和错误检测逻辑后,服务端执行到打印sent fin message completed后停止,无法输出调试语句hello world,后续的校验和计算、发送及循环退出逻辑也无法执行。
服务端运行输出:
❯ ./TestServer waiting for client... client 1 say: hello i am client sending video file completed sent fin message completed
问题原因分析
- 标准输出缓冲导致调试信息不显示:
printf默认采用行缓冲模式,无换行符的输出会暂存于缓冲区,不会立即打印到终端,造成调试语句未执行的假象。 - 客户端接收校验和时地址结构错误:客户端接收服务端校验和时,错误使用自身地址结构
client_addr,导致无法正确接收服务端数据包,双方陷入阻塞。 - 数据发送/写入长度不匹配:发送文件数据和校验和时使用固定缓冲区大小而非实际有效数据长度,接收写入文件时也未按实际接收字节数写入,可能引发文件损坏或数据冗余。
修复方案
1. 修复服务端调试输出缓冲问题
修改服务端handleClient函数中的调试打印语句,添加换行符强制刷新输出:
// 原代码 printf("hello world"); printf("buffer is %s", buffer); // 修改后 printf("hello world\n"); printf("buffer is %s\n", buffer);
2. 修复客户端校验和接收的地址结构错误
调整客户端接收校验和的recvfrom调用,使用服务端地址结构并正确初始化地址长度:
// 原代码 recvfrom(sock, message, BUFSIZE,0,(struct sockaddr*)&client_addr,&adr_sz); // 修改后 adr_sz = sizeof(serv_addr); recvfrom(sock, message, BUFSIZE, 0, (struct sockaddr*)&serv_addr, &adr_sz);
3. 修复数据发送/写入的长度匹配问题
服务端发送文件数据时使用实际读取长度:
// 原代码 sendto(clients[id].socket, buffer, BUF_SIZE, 0, (struct sockaddr *)&clients[id].address, sizeof(clients[id].address)); // 修改后 sendto(clients[id].socket, buffer, bytesread, 0, (struct sockaddr *)&clients[id].address, sizeof(clients[id].address));
客户端写入文件时使用实际接收长度:
// 原代码 fwrite(message, BUFSIZE, 1, file); // 修改后 fwrite(message, 1, nbyte, file);
服务端发送校验和时使用字符串实际长度:
// 原代码 sendto(clients[id].socket, buffer, BUF_SIZE, 0, (struct sockaddr *)&clients[id].address, sizeof(clients[id].address)); // 修改后 sendto(clients[id].socket, buffer, strlen(buffer)+1, 0, (struct sockaddr *)&clients[id].address, sizeof(clients[id].address));
修复后关键代码片段
服务端handleClient函数修改后片段
while (1) { char buffer[BUF_SIZE]; size_t bytesread = fread(buffer, 1, sizeof buffer, file); if (bytesread == 0) { printf("sending video file completed\n"); char fileFinMessage[] = "fin"; if (sendto(clients[id].socket, fileFinMessage, sizeof(fileFinMessage), 0, (struct sockaddr *)&clients[id].address, sizeof(clients[id].address)) < 0) { perror("sendto() failed"); exit(EXIT_FAILURE); } printf("sent fin message completed\n"); printf("hello world\n"); unsigned short checksum = calculateChecksum(file); sprintf(buffer, "%d", checksum); printf("buffer is %s\n", buffer); sendto(clients[id].socket, buffer, strlen(buffer)+1, 0, (struct sockaddr *)&clients[id].address, sizeof(clients[id].address)); fclose(file); break; } sendto(clients[id].socket, buffer, bytesread, 0, (struct sockaddr *)&clients[id].address, sizeof(clients[id].address)); }
客户端接收文件及校验和修改后片段
int nbyte = BUFSIZE; while(1){ adr_sz = sizeof(serv_addr); nbyte = recvfrom(sock, message, BUFSIZE, 0, (struct sockaddr*)&serv_addr, &adr_sz); if(!strcmp(message, "fin")){ printf("File received success \n"); break; } fwrite(message, 1, nbyte, file); } adr_sz = sizeof(serv_addr); recvfrom(sock, message, BUFSIZE, 0, (struct sockaddr*)&serv_addr, &adr_sz); printf("checksum = %s\n",message); unsigned short checksum = calculateChecksum(file); char checksumCheck[BUFSIZE]; sprintf(checksumCheck, "%d", checksum); if(!strcmp(message,checksumCheck)){ printf("checksum correct\n"); } fclose(file); close(sock);
内容的提问来源于stack exchange,提问作者user24723398
相关产品推荐
相关产品推荐

