2017-09-27 189 views
1

我在我的應用程序中有一個TCP客戶端和一個TCP服務器類。 客戶端發送小字符串,例如「1 | 2 |」或「1 | 11 |」TCP客戶端發送數據,但TCP服務器收到空

Client類

public class TcpClient { 


private static final int MAX_DATA_RETRY = 1; 
private static final int PING_TIMEOUT = 100; 

private ClientThread thread; 
private boolean mRun = true; 
private PrintWriter mBufferOut; 

private String mIPAdress; 


private ArrayList<BufferDataItem> messageBuffer = new ArrayList<BufferDataItem>(); 
private Socket mSocket; 

public TcpClient() 
{ 
    thread = new ClientThread(); 
    thread.start(); 
} 

private class ClientThread extends Thread { 

    @Override 
    public void run() { 

     while(mRun) 
     { 
      if(messageBuffer.size() <= 0) 
       continue; 

      BufferDataItem currMessage = messageBuffer.get(0); 
      currMessage.retryCount++; 
      if(currMessage.retryCount > MAX_DATA_RETRY) 
      { 
       messageBuffer.remove(0); 
       continue; 
      } 

      try { 
       //here you must put your computer's IP address. 
       InetAddress serverAddr = InetAddress.getByName(currMessage.ip); 



       //Log.e("TCP Client", "C: Connecting..."); 

       try { 
        if(!serverAddr.isReachable(PING_TIMEOUT)) 
        { 
         //only attempt to connect to devices that are reachable 
         messageBuffer.remove(0); 
         continue; 
        } 


        //create a socket to make the connection with the server 
        mSocket = new Socket(serverAddr, TcpManager.SERVER_PORT); 

        //Log.i("TCP Debug", "inside try catch"); 
        //sends the message to the server 

        mBufferOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream())), true); 

        String message = currMessage.message; 
        if (mBufferOut != null && !mBufferOut.checkError()) { 
         Log.d("TCP SEND", "PUTTING IN BUFFER! " + message); 
         mBufferOut.println(message); 
         listener.messageSent(message, currMessage.ip); 
         messageBuffer.remove(0); 
        } 
        mBufferOut.flush(); 

       } 
       catch (ConnectException e) { 
        //Connection refused by found device! 
        //Log.e("TCP", "C: ConnectException ip = "+currMessage.ip, e); 
        listener.hostUnreachable(currMessage.ip); 
        continue; 
       } 
       catch (Exception e) { 
        Log.e("TCP", "S: Error", e); 
        listener.messageSendError(e); 
       } 
       finally { 
        if(mSocket != null) 
         mSocket.close(); 
       } 

      } 
      catch (Exception e) { 
       Log.e("TCP", "C: Error", e); 
       listener.messageSendError(e); 
       continue; 
      } 
     } 
    } 
} 



/** 
* Sends the message entered by client to the server 
* 
* @param message text entered by client 
*/ 
public void sendMessage(String message) { 

    BufferDataItem data = new BufferDataItem(); 
    data.message = message; 
    data.ip = mIPAdress; 
    messageBuffer.add(data); 
} 

public void sendMessage(String message, String ip) { 
    mIPAdress = ip; 
    BufferDataItem data = new BufferDataItem(); 
    data.message = message; 
    data.ip = mIPAdress; 
    messageBuffer.add(data); 
} 


/** 
* Close the connection and release the members 
*/ 
public void stopClient() { 
    Log.i("Debug", "stopClient"); 

    mRun = false; 

    if (mBufferOut != null) { 
     mBufferOut.flush(); 
     mBufferOut.close(); 
    } 
    mBufferOut = null; 
} 

private class BufferDataItem 
{ 
    public String message = ""; 
    public int retryCount = 0; 
    public String ip = ""; 
} 

private OnMessageSent listener = null; 

public interface OnMessageSent { 
    public void messageSent(String message, String ip); 

    public void hostUnreachable(String ip); 

    public void messageSendError(Exception e); 

} 

public void setMessageSentListener(OnMessageSent listener) 
{ 
    this.listener = listener; 
} 

public void removeMessageSentListener() 
{ 
    this.listener = null; 
} 

}

服務器類

public class TcpServer { 

private ServerThread thread; 
private boolean mRun = true; 
private boolean mEnd = false; 


public TcpServer() 
{ 
    thread = new ServerThread(); 
    thread.start(); 
} 

private class ServerThread extends Thread { 

    @Override 
    public void run() { 

     try { 
      Boolean end = false; 
      ServerSocket ss = new ServerSocket(TcpManager.SERVER_PORT); 
      while (mRun) { 
       //Server is waiting for client here, if needed 
       Socket s = ss.accept(); 
       BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream())); 
       //PrintWriter output = new PrintWriter(s.getOutputStream(), true); //Autoflush 
       String st = input.readLine(); 
       String remoteIP = s.getRemoteSocketAddress().toString(); 
       int index = remoteIP.indexOf(":"); 
       remoteIP = remoteIP.substring(1,index); 

       Log.d("TCP READ", "TCP READ: " + st); 
       if(st != null) 
        listener.messageReceived(st, remoteIP); 
       //output.println("Good bye and thanks for all the fish :)"); 

       if(mEnd) 
       { 
        s.close(); 
        mRun = false; 
       } 
      } 

      ss.close(); 


     } catch (UnknownHostException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

//Declare the interface. The method messageReceived(String message) will must be implemented in the MyActivity 
//class at on asynckTask doInBackground 
public interface OnMessageReceived { 
    public void messageReceived(String message, String ip); 
} 

private OnMessageReceived listener = null; 

public void SetMessageReceivedListener(OnMessageReceived listener) 
{ 
    this.listener = listener; 
} 

public void RemoveMessageReceivedListener() 
{ 
    this.listener = null; 
} 

}

這工作正常運行的最初幾次,然後但隨後的客戶端發送「 1 | 11 |」並且服務器在readLine期間將st設置爲null。 String st = input.readLine();

有沒有人有任何建議?

+0

的ArrayList是不是線程安全的容器。客戶端代碼修改來自不同線程的'messageBuffer',而不需要任何同步。 –

+0

而且'mEnd'在服務器代碼中從不設置爲true。所以服務器從不關閉客戶端套接字和關聯的流 - >資源泄漏。 –

+0

謝謝那個Zaboj。我必須承認多線程是否會讓我頭腦發熱。你能否建議線程安全的替代ArrayList?對於服務器,我認爲套接字必須保持打開狀態,以便它可以繼續接收正在進行的數據。情況並非如此嗎? – Dan

回答

0

我看到兩個可能的原因爲什麼服務器一段時間後沒有收到有效數據。

  1. 服務器不會關閉套接字s因爲mEnd永遠不會設置爲true。客戶端爲每條消息打開一個新的TCP連接。服務器爲連接創建一個套接字,但它永遠不會關閉套接字,並且連接的服務器端保持打開狀態。這是資源泄漏,可能會導致問題。

  2. 客戶端使用ArrayList<BufferDataItem> messageBufferArrayList不是線程安全集合,並且使用多個線程中的messageBuffer。這裏使用synchronizedList是安全的。見How do I make my ArrayList Thread-Safe? Another approach to problem in Java?Concurrent threads adding to ArrayList at same time - what happens?

相關問題