2017-09-27 663 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?