【问题标题】:Server recieves message after client disconnects客户端断开连接后服务器收到消息
【发布时间】:2016-07-26 06:39:20
【问题描述】:

在我的项目中,有一个服务器为客户服务并为他们服务。

服务器----主

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

    }

这是在 main 方法中,服务器创建一个无限循环(线程)来接受传入的连接。一旦接收到连接,服务器将创建一个新的 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 方法中,对象被实例化,然后有一个无限循环,假设打印来自客户端的任何传入消息。

当客户端断开连接时循环会中断,这就是close() 方法被调用,优雅地关闭和释放资源。至此,线程结束。

客户端 - (Android)

    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类,服务器就收不到消息了。

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

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

【问题讨论】:

  • 为什么有两个异步任务?
  • @Pooya 据我了解,我没有关闭连接。当 Android 客户端终止应用程序时,连接将关闭。当应用程序关闭时,它将向服务器返回 0 或 -1,而 BufferedReader 对象将读取此值并跳出循环,然后关闭流和套接字。
  • @Pooya 一个AsyncTask用于连接服务器,另一个AsynTask用于向服务器发送数据。
  • 只是一个疯狂的猜测,但值得一试:将“writer”值更改为:writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true);
  • @Pooya 不起作用,通过此修改,服务器在客户端连接时不会收到消息。当客户端断开连接时,服务器会收到消息。

标签: java android multithreading sockets android-asynctask


【解决方案1】:

你在读行,但不是在写行。向正在发送的消息添加行终止符,或使用println() 而不是write()

【讨论】:

  • 你说我在读行,它在服务器上。 BufferedReader 对象使用 readLine() 方法来读取我认为的传入数据包?我不明白您所说的“向正在发送的消息添加行终止符”是什么意思,但是使用 printLn() 方法确实有效。我不明白为什么要实现“写入”方法。我会查看 API 文档。
  • 我不知道你期望一个名为readLine() 的方法做什么,但它,错误,读取一行。行终止符是"\r\n", "\r",或"\n",或System.lineSeparator()println(( 添加行终止符。所有这些都在 Javadoc 中。
猜你喜欢
  • 2019-11-09
  • 1970-01-01
  • 2018-02-09
  • 2012-05-02
  • 1970-01-01
  • 2020-07-21
  • 2013-03-28
  • 1970-01-01
  • 2014-11-04
相关资源
最近更新 更多