客户端/服务器 Swing 程序在使用线程时卡住 [英] Client/server Swing program getting stuck when using Threads

查看:147
本文介绍了客户端/服务器 Swing 程序在使用线程时卡住的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 Java 程序有问题.我有这个代码:

I have a problem with my Java program. I have this codes:

Host.java:

public class Host {
protected static void start(JFrame window) {
    ServerSocket server = null;
    try {
        server = new ServerSocket();
        SocketAddress addr = new InetSocketAddress(hostname, port);
        server.bind(addr);

        Socket socket = server.accept();

        window.setVisible(false);

        Thread thread = new Thread(new Incomming(socket.getInputStream()));
        thread.start();
        thread.join();

        socket.close();
    } catch (UnknownHostException e) {
        [...]
}
}

Incomming.java:

public class Incomming implements Runnable {
private DataInputStream is;

public Incomming(InputStream is) {
        MyFrame frame = new MyFrame();
    frame.setVisible(true);
    frame.pack();

    this.is = new DataInputStream(is);
}

public void run() {
    try {
        while(!Thread.currentThread().isInterrupted()) {
            int n = is.readInt();
            if(n == -1) {
                break;
            }
            byte[] b = new byte[n];
            is.readFully(b);
            [...] // working with bytes
        }
        System.out.println("Stream closed.");
    } catch(IOException e) {
        [...]
    }
}
}  

Client.java 与 Host.java 非常相似,它也将 Incomming.java 用于 socket.getInputStream().

Client.java is very similar to Host.java, it uses Incomming.java for socket.getInputStream() too.

所以问题是:客户端连接到主机,但是当它应该在服务器端和客户端显示 MyFrame 窗口时,它没有完全加载它.旧 JFrame 窗口(两侧)的关闭按钮没有任何作用.

So the problem is: the client connects to the host, but when it should show on server side and also on client side the MyFrame window, it doesn't load it fully. And the close button of old JFrame windows (on both sides) doesn't do anything.

我尝试使用 thread.join() 删除该行,然后 MyFrame 窗口完全加载并关闭按钮工作,但它在 socket closed 时引发异常消息,因此客户端不再连接到主机.

I tried to remove the line with thread.join(), and then the MyFrame window loads completely and close buttons work, but it throws me exception with socket closed message, so the client is no longer connected to the host.

我该如何解决这个问题?感谢回复.

How could I fix this problem? Thanks for replies.

推荐答案

  1. Thread#join 将阻塞直到线程死亡.这会阻止您关闭窗口,因为您正在阻止事件调度线程.有关详细信息,请参阅 Swing 中的并发.
  2. 接受一个传入的套接字,启动一个新的线程来处理该套接字,然后立即关闭该套接字(很可能在线程甚至有机会启动之前从中读取).相反,一旦它完成了对流的处理,就关闭线程内的套接字
  1. Thread#join will block until the thread dies. This is preventing you from closing your window, as you are blocking the Event Dispatching Thread. See Concurrency in Swing for more details.
  2. You accept an incoming socket, start a new Thread to process that socket and then promptly close the socket (most likely before the thread has had a chance to even start reading from it). Instead, close the socket inside the thread, once it has competed processing the stream

更新

Swing 是一个单线程框架.这意味着与 UI 的所有交互(创建、修改)都必须在事件调度线程的上下文中执行.任何阻塞该线程的操作都会阻止 EDT 处理事件,包括重绘、鼠标和键盘事件.

Swing is a single threaded framework. This means that all interactions with the UI (creation, modification) MUST be executed within the context of the Event Dispatching Thread. Any operation that blocks this thread will stop the EDT from processing events, including repaint, mouse and keyboard events.

与其将套接字的输入 put 流传递给线程,不如将套接字传递给线程.这会将管理套接字的责任传递给该线程,从而释放您当前的线程.

Instead of passing the socket's input put stream to the thread, you should pass the socket. This passes responsibility for the management of the socket to that thread, freeing up you current thread.

然后在您的 Incomming 类中,您应该获取对套接字输入流的引用,执行您需要的任何操作,最后,在以下情况下关闭输入 put 流和套接字大功告成.

Then in your Incomming class, you should grab a reference to the input stream of the socket, perform what ever actions you need to and the, finally, close both the input put stream and socket when you are done.

protected static void start(JFrame window) {
        ServerSocket server = null;
        try {
            server = new ServerSocket();
            SocketAddress addr = new InetSocketAddress(hostname, port);
            server.bind(addr);

            Socket socket = server.accept();

            window.setVisible(false);

            // Pass the socket to the thread to allow it to perform the work
            Thread thread = new Thread(new Incomming(socket));
            thread.start();

        } catch (IOException ex) {
            //...//
        }

    }

public class Incomming implements Runnable {

    private final Socket socket;

    public Incomming(Socket socket) {
        //?? What's this for, this is VERY wrong
        // UI Interaction should ONLY occur within the context of the EDT
        MyFrame frame = new MyFrame();
        frame.setVisible(true);
        frame.pack();

        this.socket = socket;

    }

    public void run() {
        if (socket != null) {
            DataInputStream is = null;
            try {
                is = new DataInputStream(socket.getInputStream());
                while (!Thread.currentThread().isInterrupted()) {
                    int n = is.readInt();
                    if (n == -1) {
                        break;
                    }
                    byte[] b = new byte[n];
                    is.readFully(b);
                    //...//
                }
                System.out.println("Stream closed.");
            } catch (IOException e) {
            } finally {
                // Finally clean up...
                try {
                    is.close();
                } catch (Exception e) {
                }
                try {
                    socket.close();
                } catch (Exception e) {
                }
            }
        }
    }
}

必须阅读Swing 中的并发

如果您打算在处理套接字时更新 UI,您很可能希望使用 SwingWorker 而不是 Thread.这提供了额外的功能,可以更轻松地将更新同步回事件调度线程

If you intend to update the UI while processing the socket, you will most likely want to use a SwingWorker instead of a Thread. This provides additional functionality to make it easier to sync updates back to the Event Dispatching Thread

这篇关于客户端/服务器 Swing 程序在使用线程时卡住的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆