Android的TCP应用程序挂在inStream.readline() [英] Android TCP app hanging on inStream.readline()

查看:321
本文介绍了Android的TCP应用程序挂在inStream.readline()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个延续的<一个href="http://stackoverflow.com/questions/11847092/android-tcp-does-not-flush-until-socket-is-closed/11848643#comment15771685_11848643">this问题因为我的原单问题得到回答,但它并没有解决问题。

问:

  • 如何解决code挂在这条线的 inStream.readline()

我的意图:

  1. 这是在一个线程,将通过检查,如果有一个outMessage循环,如果有,则发送消息。
  2. 在接下来它会检查是否有在河道内,如果有,它会在我的主要活动发送到处理任何事情。
  3. 最后,它会睡1秒钟,然后再次检查。
  4. 这应该让我读/写多次,而无需关闭和打开插座。

问题:

  • 这是读,写更好,但仍然不能正常工作

现在发生的事情:

  • 如果outMessage与一个值进行初始化,在与所述服务器中,插座连接:
    1. 写入并刷新值(服务器接收及放大器;响应)
    2. outMessage到
    3. 更新值(为空或X根据我怎么把它硬codeD)
    4. 读取并显示从服务器
    5. 响应消息
    6. 重新进入下一个循环
    7. 如果我设置outMessage为空,那么它跳过,如果语句正确后挂起;否则,如果我设置outMessage为一个字符串(可以说X),它会在整个if语句,然后挂起。
      • 的code它的挂起是的 inStream.readline()电话(我现在有一个注释)。

附加信息:   - 一旦连接,我可以键入送中,提交(更新outMessage值),然后断开。在重新连接时,它会读取值,并再次进行序列,直到它卡住在同一条线上。

由于引用的问题更改: - 制造outMessage和connectionStatus既有动荡 - 增加生产线末端的分隔符的neccesary地方

code:

 公共无效的run(){
            而(connectionStatus!= TCP_SOCKET_STATUS_CONNECTED){
                尝试 {
                    视频下载(500);
                }赶上(InterruptedException异常E){
                    e.printStackTrace();
                }
            }
            而(connectionStatus == TCP_SOCKET_STATUS_CONNECTED){
                尝试 {
                    如果(outMessage!= NULL){
                        OutStream.writeBytes(outMessage +\ N);
                        OutStream.flush();
                        sendMessageToAllUI(0,MAINACTIVITY_SET_TEXT_STATE,appendText,走出去SERVER:+ outMessage);
                        outMessage =×;
                    }
                    视频下载(100);
 //如果(InStream.readLine()长度()&GT; 0){
                        串modifiedSentence = InStream.readLine();
                        sendMessageToAllUI(0,MAINACTIVITY_SET_TEXT_STATE,appendText,从服务器:+ modifiedSentence);
//}
                    视频下载(1000);
                }赶上(IOException异常E){
                    失去连接();
                    打破;
                }赶上(InterruptedException异常E){
                    e.printStackTrace();
                }
            }
        }
 

这使得插座上的螺纹:

 公共无效的run(){
        的setName(AttemptConnectionThread);
        connectionStatus = TCP_SOCKET_STATUS_CONNECTING;
        尝试 {
            SocketAddress的套接字地址=新的InetSocketAddress(服务器IP,端口);
            tempSocketClient =新的Socket(); //创建一个未绑定的套接字

            //此方法将阻塞,不超过timeoutMs更多。如果出现超时,SocketTimeoutException如果被抛出。
            tempSocketClient.connect(套接字地址timeoutMs);
            OutStream =新DataOutputStream类(tempSocketClient.getOutputStream());
            视频插播广告=新的BufferedReader(新的InputStreamReader(tempSocketClient.getInputStream()));
            socketClient = tempSocketClient;
            socketClient.setTcpNoDelay(真正的);
            连接();
        }赶上(UnknownHostException异常E){
            连接失败();
        }赶上(SocketTimeoutException如果E){
            连接失败();
        }赶上(IOException异常E){
            //关闭套接字
            尝试 {
                tempSocketClient.close();
            }赶上(IOException异常E2){
            }
            连接失败();
            返回;
        }
    }
 

服务器:

 公共静态无效的主要(字串[] args)抛出IOException异常{
    字符串clientSentence;
    字符串capitalizedSentence;
    尝试 {
        ServerSocket的welcomeSocket =新的ServerSocket(8888);
        SERVERIP = getLocalIpAddress();
        的System.out.println(!连接并等待客户端输入\ n收听的IP:+ SERVERIP +\ñ\ N);
        插座connectionSocket = welcomeSocket.accept();
        的BufferedReader inFromClient =新的BufferedReader(新的InputStreamReader(connectionSocket.getInputStream()));
        DataOutputStream类outToClient =新DataOutputStream类(connectionSocket.getOutputStream());
        而(真)
        {
            尝试 {
                视频下载(1000);
            }赶上(InterruptedException异常E){
                // TODO自动生成的catch块
                e.printStackTrace();
            }
            clientSentence = inFromClient.readLine();
            的System.out.println(clientSentance ==+ clientSentence);
            。字符串IP = connectionSocket.getInetAddress()的toString()子(1)。
            如果(clientSentence!= NULL)
            {
                的System.out.println(以从客户端(+ IP +)(+ System.currentTimeMillis的()+):+ clientSentence);
                capitalizedSentence = clientSentence.toUpperCase()+'\ N';
                outToClient.writeBytes(capitalizedSentence +'\ N');
                的System.out.println(出到客户端(+ IP +):+ capitalizedSentence);
            }
        }
    }赶上(IOException异常E){
        //如果服务器已经在运行,它不会打开新的端口,而是重新打印打开的端口信息
         SERVERIP = getLocalIpAddress();
         的System.out.println(!连接并等待客户端输入的\ n);
         的System.out.println(听的IP:+ SERVERIP +\ñ\ N);

    }
}
 

在此先感谢!

编辑:

  • 添加服务器code,敬请谅解
  • 在我试图与设置SoTimout套接字插科打诨,但把该退了出去
解决方案

您需要检查是否有可用数据:

 如果(InStream.available&GT; 0){
   串modifiedSentence = InStream.readLine();
   sendMessageToAllUI(0,MAINACTIVITY_SET_TEXT_STATE,appendText,从服务器:+ modifiedSentence);
}
 

不过说实话,即使是因为你没有出示担保的eond - - 行会已经接收不理想。如果服务器发送几个字节,但从未将最终的行,那么你依然会阻止永远。生产插座code,决不能依赖的readLine 而是读入缓冲区,检查缓冲区结束的行(或任何标准的协议需要)。


没看过不够密切,我想插播是一个的InputStream 实例。 的InputStream 可用 InputStreamReader的就绪(这反过来又要求 InputStream.available 。只要你保持refernce要么这些,那么你可以看到,如果可以读取数据。

This is a continuation of this question because it my orginal question was answered, but it did not solve the bug.

Question:

  • How do I fix the code hanging on this line inStream.readline()

My Intent:

  1. This is in a thread that will loop through checking if there is an outMessage, if there is, it will send the message.
  2. Next it will check it if there is anything in the in-stream, if there is, it will send it to the handler in my main activity.
  3. Lastly, it will sleep for 1 second, then check again.
  4. This should allow me to read/write multiple times without needing to close and open the socket.

Problem:

  • It is reading and writing better, but still not working properly

What is happening now:

  • If outMessage is initialized with a value, upon connection with the server, the socket:

    1. writes and flushes the value (server receives & responds)
    2. updates value of outMessage (to null or to "x" depending on how i have it hard-coded)
    3. reads and shows the response message from the server
    4. re-enters for the next loop
    5. IF i set outMessage to null, it skips over that if statements correctly then hangs; otherwise, if i set outMessage to a string (lets say "x"), it goes through the whole if statement, then hangs.
      • The code it hangs on is either of the inStream.readline() calls (I currently have one commented out).

Additional info: - once connected, I can type in the "send" box, submit (updates the outMessage value), then disconnect. Upon re-connecting, it will read the value and do the sequence again until it get stuck on that same line.

Changes since the referenced question: - Made outMessage and connectionStatus both 'volatile' - added end-of-line delimiters in neccesary places.

Code:

        public void run() { 
            while (connectionStatus != TCP_SOCKET_STATUS_CONNECTED) {
                try {
                    Thread.sleep(500);  
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            while (connectionStatus == TCP_SOCKET_STATUS_CONNECTED) {
                try {   
                    if (outMessage != null){                                            
                        OutStream.writeBytes(outMessage + "\n");                    
                        OutStream.flush();                                          
                        sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "OUT TO SERVER: " + outMessage);
                        outMessage = "x";                                           
                    }                                                           
                    Thread.sleep(100);
 //             if (InStream.readLine().length() > 0) {                             
                        String modifiedSentence = InStream.readLine();              
                        sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "IN FROM SERVER: " + modifiedSentence);
//                  }                                                   
                    Thread.sleep(1000);
                } catch (IOException e) {                               
                    connectionLost();
                    break;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }                               
        }

The thread that makes the socket:

public void run() {
        setName("AttemptConnectionThread");
        connectionStatus = TCP_SOCKET_STATUS_CONNECTING;
        try {
            SocketAddress sockaddr = new InetSocketAddress(serverIP, port);
            tempSocketClient = new Socket(); // Create an unbound socket

            // This method will block no more than timeoutMs. If the timeout occurs, SocketTimeoutException is thrown.
            tempSocketClient.connect(sockaddr, timeoutMs);
            OutStream = new DataOutputStream(tempSocketClient.getOutputStream());
            InStream = new BufferedReader(new InputStreamReader(tempSocketClient.getInputStream()));
            socketClient = tempSocketClient;
            socketClient.setTcpNoDelay(true);
            connected(); 
        } catch (UnknownHostException e) {
            connectionFailed();
        } catch (SocketTimeoutException e) {
            connectionFailed();
        } catch (IOException e) {
            // Close the socket
            try {
                tempSocketClient.close();
            } catch (IOException e2) {
            }
            connectionFailed();
            return;
        }
    } 

Server:

public static void main(String[] args) throws IOException {
    String clientSentence;
    String capitalizedSentence;
    try {
        ServerSocket welcomeSocket = new ServerSocket(8888);
        SERVERIP = getLocalIpAddress();
        System.out.println("Connected and waiting for client input!\n Listening on IP: " + SERVERIP +"\n\n");
        Socket connectionSocket = welcomeSocket.accept();
        BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
        DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
        while(true)
        {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            clientSentence = inFromClient.readLine();
            System.out.println("clientSentance == " + clientSentence);
            String ip = connectionSocket.getInetAddress().toString().substring(1);
            if(clientSentence != null)
            {
                System.out.println("In from client ("+ip+")("+ System.currentTimeMillis() +"): "+clientSentence);
                capitalizedSentence = clientSentence.toUpperCase() + '\n';
                outToClient.writeBytes(capitalizedSentence + '\n');
                System.out.println("Out to client ("+ip+"): "+capitalizedSentence);
            }
        }
    } catch (IOException e) {
        //if server is already running, it will not open new port but instead re-print the open ports information
         SERVERIP = getLocalIpAddress();
         System.out.println("Connected and waiting for client input!\n");
         System.out.println("Listening on IP: " + SERVERIP +"\n\n");

    }
}

Thanks in advance!

Edits:

  • added the server code after updating
  • I tried messing around with setting the SoTimout for the socket but took that back out

解决方案

You need to check if there is data available:

if (InStream.available > 0) {                                                      
   String modifiedSentence = InStream.readLine();
   sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "IN FROM SERVER: " + modifiedSentence); 
}

But to be honest, even that is not ideal because you have no gurantee that the eond-of-line will have been received. If the server sends a few bytes but never sends the end-of-line then you will still be blocking forever. Production socket code should never rely on readLine but instead read into a buffer and check that buffer for end-of-line (or whatever criteria your protocol needs).


Didn't read closely enough, I thought InStream was an InputStream instance. InputStream has available. InputStreamReader has ready (which in turn calls InputStream.available. As long as you keep a refernce to either of these then you can see if data is available to be read.

这篇关于Android的TCP应用程序挂在inStream.readline()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆