You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android客户端Socket发图后提前关闭无法接收服务端回执如何解决

解决方案

核心问题原因

  • TCP是流式传输协议,没有天然的数据边界,你直接发送图片字节,服务端无法判断图片是否传输完成,会一直阻塞在recv调用等待新数据,不会触发回执返回逻辑。
  • Java Socket的输出流调用close()会直接关闭整个Socket关联的所有IO通道,输入流也会同步失效,自然无法接收服务端返回的回执。
  • 客户端当前代码中while (isSocketOpen)是死循环,只要isSocketOpen没有被主动设为false,就会重复发送图片数据,导致服务端接收的文件体积持续变大。
  • 服务端的回执发送逻辑错误写在了文件写入异常的except块中,正常保存图片成功的场景根本不会发送回执;且recv返回空仅当客户端主动断开连接时才会触发,正常传输完成不会进入该分支。

修改后的Python服务端代码

from socket import *
import uuid
import struct

port = 9999
s = socket(AF_INET, SOCK_STREAM)
s.bind(('', port))
s.listen(1)

while True:
    conn, addr = s.accept()
    img_dir = '/home/Desktop/frames_saved/'
    img_format = '.png'
    try:
        print("Connected by ", addr)
        filename = str(uuid.uuid4())
        # 先读取4字节的图片长度(大端字节序)
        len_data = conn.recv(4)
        img_len = struct.unpack('!I', len_data)[0]
        # 接收对应长度的图片数据
        received_data = b''
        while len(received_data) < img_len:
            chunk = conn.recv(min(1024*8, img_len - len(received_data)))
            if not chunk:
                break
            received_data += chunk
        # 保存图片
        with open(img_dir+filename+img_format, 'wb') as file:
            file.write(received_data)
        # 发送回执,末尾加换行符适配客户端readLine接口
        conn.sendall("接收成功\n".encode('utf-8'))
    except Exception as e:
        print(f"处理出错: {e}")
        conn.sendall("接收失败\n".encode('utf-8'))
    finally:
        conn.close()

修改后的Android客户端代码

public class SendImageClient extends AsyncTask<byte[], Void, String> {

    @Override
    protected String doInBackground(byte[]... voids) {
        Socket socket = null;
        DataOutputStream dataOutputStream = null;
        BufferedReader input = null;
        String response = null;
        try {
            socket = new Socket("192.168.0.14",9999);
            dataOutputStream = new DataOutputStream(socket.getOutputStream());
            input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            byte[] imgData = voids[0];
            // 先发送4字节的图片长度(大端字节序,和服务端对应)
            dataOutputStream.writeInt(imgData.length);
            // 发送图片内容
            dataOutputStream.write(imgData, 0, imgData.length);
            dataOutputStream.flush();
            // 等待接收服务端回执
            response = input.readLine();
            Log.d("[回执内容]", response);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 统一回收资源,避免提前关闭Socket
            try {
                if (input != null) input.close();
                if (dataOutputStream != null) dataOutputStream.close();
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return response;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        // 主线程弹出Toast
        if (result != null) {
            Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(MainActivity.this, "传输失败", Toast.LENGTH_SHORT).show();
        }
    }
}

注意事项

  • 如果需要多次传输图片,不要每次传输都新建Socket,可以复用同一个Socket连接,每次都遵循「发长度→发内容→等回执」的逻辑即可。
  • 实际生产环境建议加上超时逻辑,避免网络异常时线程长时间阻塞。

内容的提问来源于stack exchange,提问作者user1159788

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 07:36:09