如何通过SSL Socket带缓冲区发送byte[]至服务器?求助
问题排查与解决方案
咱们先从日志里最显眼的错误说起:java.io.FileNotFoundException: [B@838f46d (No such file or directory),这个问题直接导致了代码抛出异常,先解决它,再处理其他潜在问题。
1. 客户端核心错误:错误的File对象创建
在你的Android客户端代码里,这一行是问题根源:
File file = new File(String.valueOf(bytes));
当你把byte[]直接转成字符串时,得到的是[B@xxxxxx格式的数组内存标识,这不是任何合法的文件路径,所以后续尝试创建FileInputStream时自然找不到文件。
更关键的是:你已经把图片资源转成了bytes数组,完全不需要再通过FileInputStream读取它!这一步操作完全多余,直接用已经生成的bytes数组写入Socket输出流即可。
2. Android主线程网络操作问题
从日志能看出,你在onCreate方法(主线程)里执行了Socket连接和数据发送操作。Android从API 11开始就禁止在主线程进行网络IO,会抛出NetworkOnMainThreadException(可能你测试的设备版本较低暂时没触发,但这是严重的潜在问题),必须把网络操作放到子线程中。
3. Python服务器的几个问题
- 你把
sock.close()放在了while循环内部,这会导致服务器处理完第一个客户端连接后就关闭监听Socket,无法接受后续连接,必须把它移到循环外部。 - 客户端发送的是JPEG格式图片(
Bitmap.CompressFormat.JPEG),但服务器保存为.png文件,这会导致生成的文件无法正常打开,需要统一格式。 - 缺少异常处理,一旦某个客户端连接出错,服务器会直接崩溃,需要添加异常捕获逻辑。
修正后的客户端代码(Android)
// 在onCreate方法中启动子线程执行网络操作 new Thread(new Runnable() { @Override public void run() { byte[] bytes = null; Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.test); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.JPEG, 100, stream); bytes = stream.toByteArray(); // 更新UI必须在主线程执行 runOnUiThread(new Runnable() { @Override public void run() { ImageView mImageView = findViewById(R.id.imageView2); Bitmap bitmap = BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.test); mImageView.setImageBitmap(bitmap); } }); if (socketConnect()) { try { Log.d("MainActivity", "Before OutputStream"); // 使用try-with-resources自动关闭流,避免资源泄漏 try (OutputStream os = sock.getOutputStream()) { os.write(bytes); os.flush(); Log.d("MainActivity", "Image data sent successfully"); } finally { // 确保Socket被关闭 if (sock != null) { sock.close(); } } Log.d("MainActivity", "End of operation"); } catch (IOException e) { e.printStackTrace(); Log.e("MainActivity", "Error sending data: " + e.getMessage()); } } else { Log.e("MainActivity", "Failed to connect to server"); } } }).start();
修正后的服务器代码(Python)
import socket import ssl sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(("", 9999)) sock.listen(10) file_index = 1 try: while True: clientsocket, (ip, port) = sock.accept() print(f"Accepted connection from {ip}:{port}") try: # 包装SSL Socket connstream = ssl.wrap_socket( clientsocket, server_side=True, certfile="server.crt", keyfile="server.key" ) # 保存为JPEG格式,和客户端压缩格式一致 with open(f'image_{file_index}.jpg', 'wb') as f: data_chunk = connstream.read(1024) while data_chunk: print("Receiving data chunk...") f.write(data_chunk) data_chunk = connstream.read(1024) print(f"Image saved as image_{file_index}.jpg") file_index += 1 except Exception as e: print(f"Error handling client connection: {str(e)}") finally: # 确保SSL连接被关闭 if 'connstream' in locals(): connstream.close() finally: # 服务器停止时才关闭监听Socket sock.close()
额外注意事项
- 确保Android客户端的
socketConnect()方法正确创建了SSL Socket,并且信任服务器的证书(如果是自签名证书,需要在客户端配置信任库)。 - 测试时确保服务器和客户端在同一网络下,并且服务器的9999端口对外开放。
内容的提问来源于stack exchange,提问作者J.Doe
相关产品推荐
相关产品推荐

