Android的TCP应用程序挂在inStream.readline() [英] Android TCP app hanging on inStream.readline()
问题描述
这是一个延续的<一个href="http://stackoverflow.com/questions/11847092/android-tcp-does-not-flush-until-socket-is-closed/11848643#comment15771685_11848643">this问题因为我的原单问题得到回答,但它并没有解决问题。
问:
- 如何解决code挂在这条线的 inStream.readline()
我的意图:
- 这是在一个线程,将通过检查,如果有一个outMessage循环,如果有,则发送消息。
- 在接下来它会检查是否有在河道内,如果有,它会在我的主要活动发送到处理任何事情。
- 最后,它会睡1秒钟,然后再次检查。
- 这应该让我读/写多次,而无需关闭和打开插座。
问题:
- 这是读,写更好,但仍然不能正常工作
现在发生的事情:
- 如果outMessage与一个值进行初始化,在与所述服务器中,插座连接:
- 写入并刷新值(服务器接收及放大器;响应) outMessage到
- 更新值(为空或X根据我怎么把它硬codeD)
- 读取并显示从服务器 响应消息
- 重新进入下一个循环
- 如果我设置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:
- This is in a thread that will loop through checking if there is an outMessage, if there is, it will send the message.
- 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.
- Lastly, it will sleep for 1 second, then check again.
- 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:
- writes and flushes the value (server receives & responds)
- updates value of outMessage (to null or to "x" depending on how i have it hard-coded)
- reads and shows the response message from the server
- re-enters for the next loop
- 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屋!