Android的TCP客户端。服务器在进程停止后才接收消息

Android的TCP客户端。服务器在进程停止后才接收消息

问题描述:

我有用Java编写的简单TCP服务器,我正在尝试为Android编写一个简单的TCP客户端,它将与在本地计算机上运行的TCP服务器进行通信。Android的TCP客户端。服务器在进程停止后才接收消息

我可以让服务器接收消息,但奇怪的是它只是在Eclipse中通过“Devices”窗口停止应用程序进程之后才接收消息。

在Android客户端上,我有主UI线程,其中包含输入IP地址和端口号的字段(这一切工作正常,所以我不包括它的代码)。当连接按钮被点击时,它启动一个新的ASyncTask来完成TCP套接字的工作。

下面是ConnectionTask类的doInBackground方法的代码:

protected Void doInBackground(Void... params) 
    { 
    String authMessage = "Authorize"; 
    boolean connected=false; 
    try 
    {   
     Socket clientSocket = new Socket(); 
     SocketAddress serverAddress = new InetSocketAddress(address,port); 
     Log.v("Connection Thread", serverAddress.toString()); 
     clientSocket.connect(serverAddress, 15); 
     if(clientSocket.isConnected()) 
     { 
      connected = true; 
      Log.v("Connection Thread", "Connection Successful"); 
      DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream()); 
      BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
      outToServer.writeBytes(authMessage); 
      Log.v("Connection Thread", "Sent Auth Message"); 
      String response = inFromServer.readLine(); 

      Log.v("TCP Client", "Response: " + response); 
      hash = computeHash(response.getBytes()); 
      //send the computed hash to the server 
      outToServer.writeBytes(hash); 
      outToServer.close(); 
      inFromServer.close(); 
      clientSocket.close(); 
     } 
     else 
     { 
      Log.v("Connection Thread", "Not Connected yet..."); 
     } 
    } 
    catch (Exception e) 
    { 
     Log.v("Connection Thread", e.getMessage()); 
    } 
    return null; 
} 

当我按下连接按钮,在模拟器中我看到的日志,“发送验证信息”,但我的服务器未收到消息“授权”直到我通过DDMS终止进程。

这里是服务器代码:

public class Server 
{ 
     private static SecureRandom random = new SecureRandom(); 
     public static void main(String argv[]) throws Exception 
     { 
      String rawClientMessage,lcClientMessage; 
      ServerSocket welcomeSocket = new ServerSocket(5000); 
      System.out.println("Starting Server..."); 
      while(true) 
      { 
       Socket connectionSocket = welcomeSocket.accept(); 
       BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream())); 
       DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream()); 
       rawClientMessage = inFromClient.readLine(); 
       if(rawClientMessage!=null) 
       { 
        lcClientMessage = rawClientMessage.toLowerCase() + '\n'; 
        System.out.println("Received Message! Contents: " + rawClientMessage); 
        if(lcClientMessage=="authorize") 
        { 
         System.out.println("Received auth request message, generating key..."); 
         String key = generateKey(); 
         //send key back 
         outToClient.writeBytes(key); 
         System.out.println("Key sent!"); 
        } 
       } 
       try 
       { 
        inFromClient.close(); 
        outToClient.close(); 
        connectionSocket.close(); 
       } 
       catch(Exception e) 
       { 
        System.out.println(e.getMessage()); 
       } 
      } 
     } 

     private static String generateKey() 
     { 
      return new BigInteger(130, random).toString(32); 
     } 
} 

编辑:

这里是一步发生了什么步骤总结:

  1. 我启动服务器(它阻止等待连接并读取“服务器启动...”)
  2. 我键入192.168.0.100端口5000到Android客户端并点击“连接”按钮
  3. 的AsyncTask是在点击创建我的套接字代码上面
  4. 没有列出的服务器控制台上尚未收到...
  5. (我可以按重新连接,也不会有事)(logcat的还读取到“发送Auth消息“日志)
  6. 我通过Eclipse设备窗口在仿真器上终止进程
  7. 服务器控制台打印:接收消息!内容:授权(如果我点击了两次连接显示两次消息)

基本上它好像它存储的信息和程序结束后,让他们全力以赴在电线上。

任何帮助表示赞赏,谢谢!可以发布更多代码,包括主UI线程和其他扩展了ASyncTask的ConnectionTask类(如果需要)。

谢谢!

+0

我认为你需要在当前服务器端的另一个while循环中读取已接受连接的字节。 – tartar 2012-04-16 06:04:28

+0

我知道这可能听起来很愚蠢,但是有什么特别的原因,您不能仅仅使用HTTP或其他现有的协议来做同样的事情? – Hassan 2012-04-16 06:24:46

+0

@tartar - 消息正常,所以它读取消息中的所有字节。 1.启动服务器 2.服务器块读“服务器开始......” 3.我在服务器上的信息Android模拟器输入到客户端 4.按连接 5.在服务器端没什么...... 6。我杀死DDMS中的进程 7.服务器上的输出显示如下: “Received Message!Contents:Authorize” – Josh 2012-04-16 06:44:35

writeBytes(message)将字节写入输出流,但它们不会沿着管道向下发送,直到流被刷新。当你杀了应用程序,流被关闭,并在流关闭之前刷新自己。

我想如果你在outToClient.writeBytes(authMessage)之后加outToClient.flush()你会摇摆。

+0

我假设你的意思是outToServer.flush()。我尝试添加 - 仍然是相同的结果(只有在程序进程停止时发送消息)。 – Josh 2012-04-16 06:37:51

+0

这个答案不正确。在'DataOutputStream'或'Socket.getOutputStream()'中没有缓冲,而且OP之间没有'BufferedOutputStream',这会激发这个建议。 – EJP 2013-03-04 22:54:05

+0

@EJP查看文档,特别是[DataOutputStream刷新](http://docs.oracle.com/javase/6/docs/api/java/io/DataOutputStream.html#flush()),你可以看到它做缓冲数据,我的答案是准确的。 OP正在使用DataOutputStream。 Bummer它没有用,但它是一个很好的尝试。 – jarvisteve 2013-03-12 02:32:17

如果您在模拟器中运行应用程序,则必须重定向您的端口。否则,您无法与服务器通信客户端。 Take a look

+0

但服务器确实收到消息,只有当我退出应用程序进程...? – Josh 2012-04-16 06:53:24

+0

我知道,您的连接将建立,您的客户端会将消息发送到服务器,但是您的服务器无法从连接的端口接收消息。您必须重定向端口,并且服务器从不同端口号接收消息。从我上面提到的超链接看看。这将帮助您如何重定向端口。 – 2012-04-16 07:14:33

+0

运行你的模拟器后。在命令提示符中键入它 - “telnet localhost ”,然后输入“redir add tcp:5000:6000”。连接端口号为5000的客户端,然后打开端口号为6000的tcp服务器。然后可以从tcp服务器接收客户端消息。 – 2012-04-16 07:19:04

您正在阅读的文章,但您并未撰写文章。 readLine()将阻塞,直到它收到一个行终止符,并且你永远不会发送一个。而且,由于您收到的数据是二进制数据,因此无论如何您都不应该试图用readLine()来读取它。重新考虑你的数据流。