C语言Socket传输位图收发字节数一致但服务端无法显示位图问题
问题根因分析
核心问题集中在变量生命周期、事件处理逻辑、GDI资源管理三类,以下是具体错误点:
- 静态变量未重置:服务端的
count、客户端的count/length都用了static修饰,单次收发完成后变量值不会复位,第二次及之后调用收发逻辑时会直接跳过循环,使用未初始化或无效的内存数据。就算是首次运行,若FD_READ被多次触发,也会因为count初始值不对导致接收逻辑异常。 - 元数据接收无校验:服务端在
FD_ACCEPT事件中直接调用一次recv读取BITMAPINFOHEADER,没有校验是否收满sizeof(BITMAPINFOHEADER)字节,一旦接收不完整,后续使用的bi.biSizeImage、bi.biWidth等核心参数全是错误值,哪怕后续图像数据接收字节数匹配也无法正常解码。 - GDI资源生命周期错误:服务端的
hdcWindow、hdcbuffer是静态变量,却在FD_READ处理完后直接释放,后续再次触发收发/绘制逻辑时,使用的是已经无效的DC句柄,CreateCompatibleBitmap、SetDIBits等GDI接口会直接调用失败。 - 绘制逻辑位置错误:直接在
FD_READ中调用BitBlt绘制到窗口DC,只要窗口触发重绘(比如拖动、缩放、被其他窗口遮挡),绘制内容就会被系统擦除,看起来就像没有显示成功。 - 无错误校验逻辑:所有Socket、GDI接口的返回值都没有做校验,无法定位是接收环节、解码环节还是绘制环节出的问题。
修复方案
按照优先级依次修改以下内容即可解决问题:
- 移除收发逻辑中临时变量的
static修饰,或者每次进入收发流程时手动复位变量:
服务端进入FD_READ时首先将count = 0;客户端进入CaptureAnImage时将count、length复位为0。 - 补充元数据接收校验,确保收满
sizeof(BITMAPINFOHEADER)字节后再使用bi的字段:int recv_len = 0; while(recv_len < sizeof(bi)) { int n = recv(cs, (char*)&bi + recv_len, sizeof(bi) - recv_len, 0); if(n <= 0) break; recv_len += n; } - 调整GDI资源生命周期:
- 要么将
hdcWindow、hdcbuffer的释放逻辑移到WM_DESTROY中,不要在FD_READ里提前释放 - 要么每次绘制时临时创建DC、使用完立即释放,不要用静态变量存储DC句柄
- 要么将
- 把绘制逻辑迁移到
WM_PAINT事件中:FD_READ收到完整位图数据后,保存好解码后的HBITMAP,调用InvalidateRect触发窗口重绘,在WM_PAINT中通过BeginPaint获取DC完成绘制,避免窗口重绘时内容丢失。 - 补充所有关键接口的返回值校验:
对recv、send、CreateCompatibleBitmap、SetDIBits的返回值做判断,失败时调用WSAGetLastError()、GetLastError()打印错误码,快速定位问题。
内容的提问来源于stack exchange,提问作者chobochobo
相关产品推荐
相关产品推荐

