Android Socket客户端无法完整读取字节数组,接收图片异常
解决Android Socket接收C#服务器图片仅显示顶部白线的问题
我帮你排查下这个问题——你遇到的情况很典型,核心原因是C#和Java默认的字节序不匹配,再加上长度读取环节的小疏漏,导致接收的图片数据不完整,最终解码后只显示顶部白线。下面一步步拆解问题和给出修复方案:
问题根源
C#的BinaryWriter默认用**小端字节序(Little-Endian)写入int类型数据(也就是低位字节排在前面),但你Android代码里解析图片长度时,用的是大端字节序(Big-Endian)**的逻辑(readMsgLen[0]<<24 | ...),这会让解析出来的长度完全错误。比如实际图片长度是1024,解析后可能变成一个超大或超小的数,导致readFully读取的字节数不对,图片数据残缺,解码后自然只显示顶部一小条白线。
另外,你用dis.read(readMsgLen,0,4)读取长度时,这个方法不一定能一次性读满4个字节,也可能导致长度解析出错。
修复步骤
1. 修正长度解析的字节序(关键!)
把解析长度的逻辑改成小端字节序,匹配C#的默认行为:
// 先确保完整读取4个字节的长度数据,用readFully代替read dis.readFully(readMsgLen, 0, 4); // 小端解析:低位字节在前,所以从readMsgLen[0]开始对应int的低位 final int length = (readMsgLen[3] & 0xFF) << 24 | (readMsgLen[2] & 0xFF) << 16 | (readMsgLen[1] & 0xFF) << 8 | (readMsgLen[0] & 0xFF);
2. 简化Bitmap加载流程(可选但推荐)
你现在把Bitmap转成Uri再用Picasso加载的流程有点绕,直接把解码后的Bitmap设置到ImageView就行,减少中间环节的潜在问题:
mn.iv.setImageBitmap(bitmap);
3. 完善异常提示
在catch块里加上UI线程的错误提示,方便你排查问题:
mn.runOnUiThread(() -> Toast.makeText(mn.getApplicationContext(), "接收图片出错:" + e.getMessage(), Toast.LENGTH_SHORT).show());
完整修正后的代码
class imageReceiver implements Runnable { Bitmap bitmap; MainActivity mn; DataInputStream dis; byte[] data; public imageReceiver(MainActivity mn) { this.mn = mn; } @Override public void run() { if (s.isConnected()) { try { final InputStream in = s.getInputStream(); dis = new DataInputStream(in); byte[] readMsgLen = new byte[4]; // 确保完整读取4个字节的长度数据 dis.readFully(readMsgLen, 0, 4); // 小端字节序解析长度,匹配C# BinaryWriter的默认输出 final int length = (readMsgLen[3] & 0xFF) << 24 | (readMsgLen[2] & 0xFF) << 16 | (readMsgLen[1] & 0xFF) << 8 | (readMsgLen[0] & 0xFF); data = new byte[length]; dis.readFully(data, 0, data.length); bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); mn.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(mn.getApplicationContext(), "图片长度:" + length, Toast.LENGTH_SHORT).show(); if (bitmap == null) { Toast.makeText(mn.getApplicationContext(), "图片解码失败", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(mn.getApplicationContext(), "图片接收成功", Toast.LENGTH_SHORT).show(); // 直接设置Bitmap到ImageView mn.iv.setImageBitmap(bitmap); } } }); } catch (IOException e) { e.printStackTrace(); mn.runOnUiThread(() -> Toast.makeText(mn.getApplicationContext(), "接收出错:" + e.getMessage(), Toast.LENGTH_SHORT).show()); } } } }
额外验证建议
- 打印Android端解析后的
length值,和C#服务器发送的实际图片字节长度对比,如果一致,说明长度解析没问题;如果不一致,那就是字节序的问题还没解决。 - 确认C#服务器是用
BinaryWriter.Write(int)发送长度的,没有手动修改字节序——如果服务器是手动构造字节数组发送长度,那需要两边的字节序逻辑完全一致。
内容的提问来源于stack exchange,提问作者Bilal Hassan
相关产品推荐
相关产品推荐

