2017-09-27 4 views
1

J'ai un client TCP et une classe de serveur TCP dans mon application. Le client envoie des petites chaînes telles que "1 | 2 |" ou "1 | 11 |"Le client TCP envoie des données mais le serveur TCP reçoit une valeur nulle

classe 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; 
} 

}

Class Server

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; 
} 

}

Cela fonctionne très bien pour les premières fois qu'elle court et puis mais le client envoie " 1 | 11 | " et le serveur définit st comme nul pendant le readLine. Chaîne st = input.readLine();

Quelqu'un a-t-il des suggestions?

+0

ArrayList n'est pas un conteneur sécurisé. Le code client modifie 'messageBuffer' de différents threads sans aucune synchronisation. –

+0

En outre, 'mEnd' n'est jamais défini sur true dans le code du serveur. Ainsi, le serveur ne ferme jamais les sockets client et les flux associés -> fuite de ressources. –

+0

merci pour ce Zaboj. Je dois admettre que le multi threading fait partie de ma tête. Pouvez-vous suggérer une alternative à ArrayList? Avec le serveur, j'ai pensé que le socket devrait rester ouvert pour pouvoir continuer à recevoir des données en cours. N'est-ce pas le cas? – Dan

Répondre

0

Je vois deux raisons possibles pour lesquelles le serveur ne reçoit pas de données valides après un certain temps.

  1. Server ne ferme pas la prise s parce que le mEnd est jamais à true. Le client ouvre une nouvelle connexion TCP pour chaque message. Le serveur crée un socket pour la connexion, mais il ne ferme jamais le socket et le côté serveur de la connexion reste ouvert. C'est une fuite de ressources et cela peut causer le problème. Le client utilise le ArrayList<BufferDataItem> messageBuffer. ArrayList n'est pas une collection thread-safe et messageBuffer est utilisé à partir de plusieurs threads. Il est sûr d'utiliser synchronizedList ici. Voir le How do I make my ArrayList Thread-Safe? Another approach to problem in Java? ou Concurrent threads adding to ArrayList at same time - what happens?