2012-04-16 78 views
1

我有用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

回答

2

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

1

如果您在模擬器中運行應用程序,則必須重定向您的端口。否則,您無法與服務器通信客戶端。 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

3

您正在閱讀的文章,但您並未撰寫文章。 readLine()將阻塞,直到它收到一個行終止符,並且你永遠不會發送一個。而且,由於您收到的數據是二進制數據,因此無論如何您都不應該試圖用readLine()來讀取它。重新考慮你的數據流。

相關問題