TCP套接字传输桌面截图一段时间后速率下降的原因排查
问题分析:TCP传输桌面截图速率下降原因
问题描述
我尝试通过TCP套接字向服务器发送桌面截图,初始时一切正常,可达约30FPS,但一段时间后传输速率变慢。我曾怀疑是内存泄漏,已在循环中删除数据并关闭文件,但问题仍存在。以下是服务器端和客户端代码,请问速率下降的具体原因是什么?
服务器端代码
while(!is_client_dead){ char file_size[1024]; recv(m_video_socket,file_size,1024,0); char *data = new char[std::atoi(file_size)]; recv(m_video_socket,data,std::atoi(file_size),0); std::fstream file("screenshot.png",std::ios::out | std::ios::binary | std::ios::trunc); for(int x{0};x<std::atoi(file_size);x++) file << data[x]; delete [] data; file.close(); cv::Mat image = cv::imread("screenshot.png"); cv::resize(image,image,cv::Size(image.cols/2,image.rows/2)); cv::imshow(m_name + "'s screen",image); cv::waitKey(1); }
客户端代码
while(!is_server_dead){ cv::Mat image; capture_screen(image); cv::imwrite("screenshot.png",image); std::size_t size = std::filesystem::file_size("screenshot.png"); send(m_client_video,std::to_string(size).c_str(),1024,0); std::ostringstream file_buffer; std::fstream file("screenshot.png",std::ios::in | std::ios::binary); file_buffer << file.rdbuf(); std::string file_data = file_buffer.str(); send(m_client_video,file_data.c_str(),size,0); file.close(); }
速率下降的核心原因
- 磁盘IO瓶颈:客户端每次将截图写入本地文件再读取发送,服务器端接收数据后也写入本地文件再读取显示。频繁的磁盘读写会随着时间积累导致IO队列阻塞,缓存耗尽后物理IO延迟大幅增加,直接拖慢整体传输速率。
- TCP传输未处理完整读写:
recv和send不保证一次性完成指定长度的读写。比如服务器端可能只接收到部分数据就继续后续操作,导致文件写入不完整、imread读取异常,长期运行积累错误状态引发卡顿;客户端send也可能未发完数据,导致服务器端等待剩余数据,拖慢传输节奏。 - 重复字符串转数字的隐患:服务器端多次调用
std::atoi(file_size),若file_size存在非法字符或转换错误,会导致内存分配、循环写入的长度出错,引发内存越界或数据不完整,长期运行积累问题导致速率下降。 - 客户端数据复制开销:用
std::ostringstream读取文件到std::string会额外复制数据,增加内存开销和处理时间,长期运行积累内存碎片,影响整体性能。
优化建议
- 跳过磁盘IO:客户端用
cv::imencode将Mat直接编码为std::vector<uchar>后发送;服务器端接收字节数组后用cv::imdecode直接解码为Mat,完全省去文件读写步骤。 - 实现可靠的TCP读写函数:封装循环调用
recv/send的函数,确保数据完全接收或发送。 - 避免重复转换:服务器端接收
file_size后只转换一次为整数,保存到变量中复用。 - 减少数据复制:客户端直接读取文件到缓冲区,避免
ostringstream和string的额外复制。
内容的提问来源于stack exchange,提问作者Aytunç Demir
相关产品推荐
相关产品推荐

