2016-04-06 205 views
3

在我的项目中,有一台服务器为客户端服务并为其提供服务。服务器在客户端断开连接后收到消息

服务器----主

ss = new ServerSocket(12345); 
    System.out.println("Server started.."); 
    while(true) 
    { 
     System.out.println("Waiting For clients..."); 
     Socket client = ss.accept(); 
     System.out.println("Got client..."); 
     Thread t = new Thread(new Handler(client)); 
     t.start(); 
     //exe.execute(new Handler(client)); 

    } 

这是主要方法,服务器创建一个无限循环(螺纹),将接受输入连接。一旦接收到连接,服务器将创建一个新的Handler对象,该对象将连接的客户端作为参数。

处理程序类

public class Handler implements Runnable { 

    Socket client; 

    public Handler(Socket client) { 
     // TODO Auto-generated method stub 
     this.client = client; 
    } 
    @Override 
    public void run() { 
     // TODO Auto-generated method stub 
     //streams 
     try { 
      OutputStream out = client.getOutputStream(); 
      PrintWriter writer = new PrintWriter(out); 

      InputStream in = client.getInputStream(); 
      BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 

      String s = null; 

      while((s=reader.readLine())!=null) 
      { 

       //will switch on string or convert to json object 
       System.out.println("Recieved: " + s); 
      } 
      writer.close(); 
      reader.close(); 
      client.close(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

    } 

} 

在这个类的主要目的是处理客户请求。所以构造函数将套接字对象初始化为它自己的实例。

在run方法中实例化对象,然后有一个无限循环,假设打印来自客户端的任何传入消息。

当客户端断开连接时,循环将中断,并且这是调用方法的地方,以正常关闭和释放资源。由此线程结束。

客户 - (安卓)

public class MainActivity extends AppCompatActivity { 

    final String ip = "192.168.0.18"; 
    final int port = 12345; 
    Socket client; 
    OutputStream out; 
    PrintWriter writer; 

    InputStream in; 
    BufferedReader reader; 
    final String TAG = "Debug: "; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     new ConnectToServer().execute(); 
     new SendToServer().execute(); 


    } 

    class ConnectToServer extends AsyncTask<Void, Void, Void> 
    { 

     @Override 
     protected Void doInBackground(Void... params) 
     { 
      try { 
       client = new Socket(ip,port); 
       //Log.d(TAG, "doInBackground: connected to server"); 
       //set streams 
       out = client.getOutputStream(); 
       writer = new PrintWriter(out); 

       in = client.getInputStream(); 
       reader = new BufferedReader(new InputStreamReader(in)); 

       Log.d(TAG, "doInBackground: Sent"); 



      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      return null; 
     } 
    } 
    class SendToServer extends AsyncTask<Void, Void, Void> 
    { 

     @Override 
     protected Void doInBackground(Void... params) { 
      writer.write("lol"); 
      writer.flush(); 
      return null; 
     } 
    } 

} 

我最后一次与Android Studio中扮演一年前左右,我非常积极的网络/ IO操作都可以对主线程上运行。但是黄金法则意味着不阻塞主线程,并且有一些阻塞方法。

我选择使用AsyncTask接口,因为它封装了更低层次的Thread类(更易于使用/了解我的生命周期)。

ConnectToServer类成功连接到服务器,但一旦调用SendToServer类,服务器就不会收到消息。

一旦我断开客户端(终止应用程序),服务器将打印出消息。

为什么服务器在客户端断开连接后收到消息?

+0

为什么你有两个异步任务? – Pooya

+0

@Pooya从我的理解,我没有关闭连接。当Android客户端终止应用程序时,连接关闭。当应用程序关闭时,它将向服务器返回一个0或-1,并且BufferedReader对象将读取并跳出循环,然后关闭流和套接字。 – Moynul

+0

@Pooya一个AsyncTask用于连接服务器,另一个AsynTask是将数据发送到服务器。 – Moynul

回答

1

您正在阅读的文章,但您并未撰写文章。在正在发送的消息中添加一个行结束符,或使用println()而不是write()

+0

你说我正在读取服务器上的行。 BufferedReader对象使用readLine()方法来读取我想要的传入数据包? 我不明白你的意思是“添加行终止符到正在发送的消息”,但是使用printLn()方法确实有效。我不明白为什么要使用“写入”方法。我将看看API文档。 – Moynul

+0

我不知道你期望一个叫做'readLine()'的方法来做什么,但是它会读取一行。行结束符是“\ r \ n”,“\ r”或“\ n”或“System.lineSeparator()”。 'println((''添加一个行结束符,所有这些都在Javadoc中。 – EJP

相关问题