【问题标题】:Android reading from Socket hangs on second read loop从 Socket 读取的 Android 在第二个读取循环上挂起
【发布时间】:2012-11-07 08:11:36
【问题描述】:

我必须在我的应用程序中实现聊天。使用套接字连接到服务器。我应该注册到该服务器,服务器会通过回复确认这一点。

我已经在一个方法中实现了这一点,我使用 BufferedWriter 发送命令,然后开始从输入流中读取,直到它告诉我没有更多数据。

我正确阅读了服务器回复。但是,我从来没有从第二个 in.read 调用中得到负值,因此我的方法在 while 循环中保持阻塞(在我进行调用的条件语句中)。

应该如何使用套接字来做到这一点?我通常对文件或其他输入流执行此操作,没有问题。

如果我应该只读取我应该读取的字节,这是否意味着我必须:

  • 提前知道服务器响应的长度?
  • 或者让服务器发送一个代码来通知它已经完成发送响应?

目前我正在做以下事情:

private String sendSocketRequest(String request, boolean skipResponse) throws ChatException {
    if (!isConnected()) openConnection();

    try {
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
                                     socket.getOutputStream()), 2048);
        out.append(request);
        out.flush();
        out = null;
    } catch (IOException e) {
        LogHelper.error("Unable to send socket request: " + request, e);
        throw new ChatException("Unable to send socket request: " + request, e);
    }

    try {
        BufferedReader in = new BufferedReader(new InputStreamReader(
                                     socket.getInputStream()), 2048);
        StringBuffer response = new StringBuffer();
        char[] buffer = new char[2048];
        int charsRead = -1;

// >>>>>>>> This is where it gets blocked <<<<<<<<<

        while ((charsRead = in.read(buffer)) >= 0) {
            if (charsRead > 0) response.append(new String(buffer, 0, charsRead));
        }
        return response.toString();
    } catch (IOException e) {
        LogHelper.error("Unable to read socket response: " + request, e);
        throw new ChatException("Unable to read socket response: " + request, e);
    }
}

使用以下方法连接到服务器:

public synchronized void openConnection() throws ChatException {
    try {
        socket = new Socket(Constants.API_CHAT_SERVER_ADDRESS, Constants.API_CHAT_SERVER_PORT);
        socket.setKeepAlive(true);

        LogHelper.debug("CHAT      >> Connected to the chat server: " + Constants.API_CHAT_SERVER_ADDRESS);
    } catch (UnknownHostException e) {
        LogHelper.error("Unable to open chat connection", e);
        throw new ChatException("Unable to open chat connection", e);
    } catch (IOException e) {
        LogHelper.error("Unable to open chat connection", e);
        throw new ChatException("Unable to open chat connection", e);
    }
}

【问题讨论】:

  • read() 在读取 2048 字节之前不会阻塞? EOF 只有在服务器关闭连接时才会收到,不是吗?

标签: java android sockets inputstream


【解决方案1】:

通过基于套接字的连接发送/接收的数据量取决于协议,TCP/IP 堆栈不知道,但只有应用层知道。

使用的协议依赖于开发人员... ;-) 所以来回答你的问题:

如果我应该只读取我应该读取的字节,这是否意味着我必须:

  • 提前知道服务器响应的长度?

是的,这是一种可能性。

  • 还是让服务器发送代码通知它已经完成发送响应?

也可以,因为这是另一种可能性。常见的标记是\n\r\nNUL/'\0' 字符也可能有意义。

第三种选择是在每个数据块前面加上一个常量字节数来描述即将到来的字节数。

【讨论】:

  • 好的,这证实了我的想法。顺便说一句,我无法触摸服务器代码,所以我必须做更多的思考:'(
【解决方案2】:

与其处理字节,也许它更简单地处理临时类的实例,例如 - 一个 Message 类:

服务器:

// Streams
protected ObjectInputStream fromBuffer = null;
protected ObjectOutputStream toBuffer = null;

// Listening for a new connection
ServerSocket serverConn = new ServerSocket(TCP_PORT);
socket = serverConn.accept();
toBuffer = new ObjectOutputStream(socket.getOutputStream());
fromBuffer = new ObjectInputStream(socket.getInputStream());

// Receiving a new Message object
Message data = (Message)fromBuffer.readObject();

然后客户端通过简单的方式发送消息:

// Sending a message
Message data = new Message("Hello");
toBuffer.writeObject(data);

Message 可以根据需要尽可能复杂,只要其成员实现 Serializable 接口即可。

【讨论】:

  • 如果我可以触摸服务器的代码,这可能是一个选择。不幸的是,我必须使用他们实施得很糟糕的“协议”(我什至称它为协议),它有时会返回一个字符串,有时会返回一个 json 对象,但从来没有任何标记来告诉这就是结束......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 2015-05-08
  • 2013-12-24
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 2021-09-30
相关资源
最近更新 更多