如何使用BufferedReader从TCP套接字读取可用文本(不以新行结尾)

时间:2015-11-07 02:33:16

标签: android multithreading sockets tcp

我通过tcp套接字连接与服务器进行通信,我能够读取以\n结尾的行,但是当行未终止时(以\n结尾)i我无法阅读它。我尝试了以下但它没有工作,导致我的应用程序在启动时冻结:

private Socket socket;
private BufferedReader input;
public boolean isConnected;

@Override
public void onCreate()
{
    try
    {
        socket = new Socket ("server.ip.add.ress", 23456);
        input = new BufferedReader (new InputStreamReader (socket.getInputStream());
        handshake();
        isConnected = true;
    }
    catch // Handle IOException and UnknownHostException
}

// custom runnable to read availabe input from the server
private class MyRunnable implements Runnable
{
    private volativle String value;
    public String getValue()
    {
        return value;
    }
    @Override
    public void run()
    {
        int count;
        char[] buffer = new char[10]; // expected message 'username: '
        try
        {
            count = input.read (buffer, 0, 10);
            if (count > 0) value = new String (buffer);
        }
        catch // IOException
    }
}

// when connection is established with server expect 'username: ' from
// the server and send the user name back to it
public void handshake()
{
    MyRunnable runnable = new MyRunnable();
    try
    {
        Thread thread = new Thread (runnable);
        thread.start();
        thread.join();
        String greeting = runnable.getValue();
        if (greeting.equals ("username: ")) // Send username back
    }
    catch // InterruptedException
}

为什么挂?以及如何读取未终止的行?

编辑:

澄清:服务器在与客户建立连接后立即发送问候消息username:,客户端等待问候并在收到时发送回用户名(这就是什么) handshake()确实如果没有握手,客户端会断开连接,否则它会开始侦听传入的消息。因为我需要知道在启动监听器之前握手是否完成,我必须使用Thread.join()

问题:感谢下面的评论和解答,结果是BufferedReader.read()阻止线程并等待直到从服务器发送内容并且如果没有发送任何内容它会导致要挂起的应用,因此无法确定线路是否已经结束

解决方案: 在我的特定情况下我只是想知道特定邮件是否已发送“用户名:”所以我使用read (buffer, 0, 10)来准确阅读10个字符(“用户名:”的长度),因为如果没有发送任何内容它会阻止我使用Thread.join (1000)只等待一秒钟然后如果没有收到我断开客户端。

2 个答案:

答案 0 :(得分:1)

为什么要挂?

这就是它的假设。如果没有可供读取的数据,它将阻止该线程。这也是你想把它放在后台线程中的原因。

如果没有可用的话,它是否可以返回?

您要找的是ready(),它会告诉您是否有可用的数据。

  

表示此阅读器是否已准备好无阻塞地阅读   的返回
  如果在读取调用时此读取器不会阻塞,则为true;如果未知或阻塞,则为false。

但使用此功能时应该非常小心。因为网络关于时间安排很多。您在此时没有读取任何数据这一事实并不意味着它不会在下一秒内成为任何数据。

因此,服务器的更好设计应该或多或少如下:

  • 如果找到用户名,请返回用户名
  • 如果找不到用户名,请返回错误消息,让客户端知道找不到用户名

答案 1 :(得分:0)

不需要线程。你的目标是等到你已经读过你一直在等待的东西。为什么不让read()执行等待你?

您正在努力解决的问题是TCP通信的经典问题:“我什么时候知道服务器发送了所有内容?”

在您的情况下,您希望读取字节,直到字节的集合以“username:”结束。因此,更改算法以执行 1字节读取(随时填充缓冲区),直到缓冲区以“username:”结束。

你可以制作一个更复杂的算法 - 这会更有效 - 它会尝试一次读取多个字节并将它们附加到缓冲区 - 每次执行检查。但这两种策略在逻辑上是等价的。

我还建议只使用InputStreamReader。它有各种read()方法。我对BufferedInputReader有点怀疑,特别是在处理非换行终止的数据时。我可能只是偏执狂。我在编写TCP客户端/服务器程序时从未使用它,所以我不确定。