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

Android客户端Socket未收到服务器返回响应问题求助

Android Socket客户端无法接收服务器响应问题排查与修复

问题描述

我在Android客户端通过Socket发送请求,尝试用另一个线程接收服务器返回的响应,但客户端始终收不到内容。打开Fragment时请求已成功发往服务器,服务器日志显示已返回响应,但客户端代码一直卡在input.readUTF()处,后续逻辑无法执行。

相关代码

Android客户端代码

public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState)
{
    binding = FragmentBinding.inflate(inflater, container, false);

    runThreads = true;
    new ResponseListener().start();
    queryAllOrders();

    return binding.getRoot();
}

private void queryAllOrders()
{
    try
    {
        if (socket != null)
        {
            DataOutputStream output = new DataOutputStream(socket.getOutputStream());
            output.writeUTF("§§Q0");
            output.flush();
            Toast.makeText(getContext(), "订单查询请求已发送", Toast.LENGTH_SHORT).show();
        }
        else
            Toast.makeText(getContext(), "订单查询失败:Socket未初始化", Toast.LENGTH_SHORT).show();
    }
    catch (IOException e)
    {
        e.printStackTrace();
        Toast.makeText(getContext(), "订单查询失败:网络异常", Toast.LENGTH_SHORT).show();
    }
}

private static class ResponseListener extends Thread
{
    @Override
    public void run()
    {
        try
        {
            DataInputStream input = new DataInputStream(socket.getInputStream());;
            while (runThreads)
            {
                String mes = input.readUTF();
                if (mes.startsWith("§§R0"))
                {
                    ContextCompat.getMainExecutor(MainApplication.getAppContext()).execute(() ->
                            Toast.makeText(MainApplication.getAppContext(), "响应接收成功", Toast.LENGTH_SHORT).show());
                    System.out.println("响应接收成功 | 消息: " + mes);
                }
                if (runThreads)
                    input = new DataInputStream(socket.getInputStream());
            }
            input.close();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

@Override
public void onDestroyView()
{
    super.onDestroyView();
    binding = null;
    runThreads = false;
}
}

服务器端处理输入的线程代码

private static class ClientInput extends Thread
{
    private final int clientId;
    private final Socket socket;

    DataInputStream input;
    DataOutputStream output;

    public ClientInput(int clientId, Socket socket) throws IOException
    {
        this.clientId = clientId;
        this.socket = socket;

        input = new DataInputStream(socket.getInputStream());
        output = new DataOutputStream(socket.getOutputStream());
    }

    @Override
    public void run()
    {
        try
        {
            while (runThreads)
            {
                String mes = input.readUTF();

                if (mes.startsWith("§§Q"))
                {
                    if (mes.charAt(3) == '0')
                    {
                        StringBuilder response = new StringBuilder("§§R0%");
                        for (Order order : orders)
                        {
                            response.append(order.toString());
                            response.append("%");
                        }
                        response.deleteCharAt(response.length() - 1);
                        serverWrite("\n已向客户端ID: " + clientId + " | 主机: " +  socket.getInetAddress().getCanonicalHostName() + "发送所有订单");
                        serverWrite("订单内容: " + response);
                        output.writeUTF(response.toString());
                        output.flush();
                    }
                }
            }
        } catch (IOException e)
        {
            if (e.getMessage() == null)
                serverWrite("\n与客户端连接断开");
            else
            {
                if (e.getMessage().equals("Connection reset"))
                    serverWrite("\n与客户端连接断开");
                else
                    e.printStackTrace();
            }
        }
    }
}

问题根源与修复方案

客户端核心问题

  1. 静态内部类无法访问非静态Socket实例:ResponseListener是静态内部类,直接访问外部类的非静态socket变量会导致拿到的实例无效(甚至为空),线程根本没在正确的连接上读取数据。
  2. 重复创建DataInputStream:每次循环都重新创建输入流,会破坏Socket输入流的读取状态,导致数据读取混乱。
  3. 线程可见性问题:runThreads是普通布尔变量,线程无法及时感知其状态变化,可能导致线程无法正常终止或逻辑异常。

具体修复步骤

1. 重构ResponseListener线程

将静态内部类改为非静态,通过构造方法传入有效Socket和线程状态变量:

private class ResponseListener extends Thread {
    private final Socket clientSocket;
    private final AtomicBoolean isRunning;

    public ResponseListener(Socket socket, AtomicBoolean running) {
        this.clientSocket = socket;
        this.isRunning = running;
    }

    @Override
    public void run() {
        // 使用try-with-resources自动管理流资源,避免泄漏
        try (DataInputStream input = new DataInputStream(clientSocket.getInputStream())) {
            while (isRunning.get()) {
                String mes = input.readUTF();
                if (mes.startsWith("§§R0")) {
                    ContextCompat.getMainExecutor(MainApplication.getAppContext()).execute(() ->
                            Toast.makeText(MainApplication.getAppContext(), "响应接收成功", Toast.LENGTH_SHORT).show());
                    System.out.println("响应接收成功 | 消息: " + mes);
                }
                // 移除重复创建输入流的代码,复用同一个流
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2. 修复线程状态变量

用AtomicBoolean替代普通布尔变量,保证多线程下的可见性:

private AtomicBoolean runThreads = new AtomicBoolean(true);

3. 启动线程时传入正确参数

// 在onCreateView中
runThreads.set(true);
new ResponseListener(socket, runThreads).start();

4. 完善Fragment销毁逻辑

确保线程终止时关闭Socket,避免资源泄漏:

@Override
public void onDestroyView() {
    super.onDestroyView();
    binding = null;
    runThreads.set(false);
    // 关闭Socket连接
    if (socket != null && !socket.isClosed()) {
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

5. 验证Socket初始化

确保socket变量是已经成功连接到服务器的有效实例,建议在Fragment创建前完成Socket连接,避免空指针或无效连接。

服务器端验证点

  • 确认orders集合为空时,响应字符串是§§R0,客户端的判断逻辑依然能匹配。
  • 检查服务器的runThreads变量是否有正确的终止逻辑,避免服务器线程异常退出导致连接断开。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 08:30:01