C++服务端与C#客户端Socket传图接收端字节不一致问题
Socket跨语言传输图片字节丢失(大量问号)问题修复方案
- 核心错误位于C#客户端的编码转换逻辑:二进制图片不属于文本格式,你将Socket接收的原始二进制数据先按Unicode规则解码为字符串、再重新编码为字节的操作,会把所有不符合Unicode编码规范的字节替换为U+FFFD替换字符,表现出来就是大量问号,直接破坏原始图片数据。
- 次要错误1:代码变量名不匹配,最终写文件时使用的
byts变量与前文存储转换结果的bits变量不一致,也会导致输出文件内容错误。 - 次要错误2:未处理TCP流的粘包/半包问题,C++的
send接口不保证一次性传输完所有字节,C#接收逻辑如果未按约定长度收全数据,会导致文件截断。
C++服务端优化(兼容长度校验逻辑)
原有读二进制文件的逻辑正确,仅需补充长度预发送和循环发送逻辑即可:
std::ifstream fin("1.bmp", std::ios::binary); std::string data; data.reserve(1000000); std::copy(std::istreambuf_iterator<char>(fin), std::istreambuf_iterator<char>(), std::back_inserter(data)); fin.close(); // 先发送4字节无符号整数标识文件总长度 uint32_t fileSize = data.size(); send(clientSocket, (char*)&fileSize, sizeof(fileSize), 0); // 循环发送确保所有字节传输完成 size_t sentBytes = 0; while (sentBytes < fileSize) { int curSent = send(clientSocket, data.c_str() + sentBytes, fileSize - sentBytes, 0); if (curSent <= 0) break; sentBytes += curSent; }
C#客户端修复(核心修改点)
删除所有文本编码转换逻辑,直接接收原始二进制字节写入文件:
s = new SocketHandler(ip, Int32.Parse(port)); // 先接收4字节文件长度 byte[] lengthBuffer = new byte[4]; s.Receive(lengthBuffer, 0, 4, SocketFlags.None); int totalLength = BitConverter.ToInt32(lengthBuffer, 0); // 按总长度接收完整二进制数据 byte[] fileBuffer = new byte[totalLength]; int receivedBytes = 0; while (receivedBytes < totalLength) { int curReceived = s.Receive(fileBuffer, receivedBytes, totalLength - receivedBytes, SocketFlags.None); if (curReceived <= 0) break; receivedBytes += curReceived; } // 直接写入原始字节到文件,无需任何转码 File.WriteAllBytes("newff.bmp", fileBuffer);
内容的提问来源于stack exchange,提问作者Maxim Kirusin
相关产品推荐
相关产品推荐

