5

我正在使用套接字编写 Java 客户端/服务器 GUI 应用程序,这就是问题所在:

我有一个按钮可以开始监听指定端口:

按钮操作执行方法

private void listenButtonActionPerformed(java.awt.event.ActionEvent evt) {                                             
    int port = Integer.parseInt(portTextfield.getText(), 10);

    try {
        socket.listen(port);
    } catch (IOException ex) {
    }
}

这是 socket.listen 方法

public static void listen() throws IOException {
    ServerSocket ss = new ServerSocket(port);

    while (true)
        new socket(ss.accept());
}

“socket”类扩展“Thread”
所以在 ss.accept() 返回一个值之后,它会在单独的线程中创建新的套接字实例。

单击按钮后,GUI 冻结,因为在 socket.listen 方法中有一个无限循环。我怎样才能避免这种情况?

4

5 回答 5

5

您的设计中有两个陷阱:

  1. ss.accept()是一个阻塞呼叫,因此您的 UI 将冻结,直到有传入连接
  2. 永远不要在 EDT 中运行while(true)循环。

而是执行以下操作:

  • 单击按钮时,创建一个线程,该线程将开始侦听传入连接。
  • 每当您有传入连接时,请创建另一个线程来接收传入的客户端连接并进行处理。
于 2012-06-25T08:36:35.887 回答
5

只要你的

new socket(ss.accept());

立即返回,您只需更改您的

while (true)

这会将 EDT(事件调度线程)置于无限循环中,并且您的 GUI 变得无响应。所以,删除这一行。

如果您不能使用 SwingWorker 类 ( http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html#process(java.util.List ) 创建一个嵌套类范围 SwingWorker。只需在您的listenButtonActionPerformed(java.awt.event.ActionEvent evt)方法中调用一个swingWoker.execute();(在您创建了它的对象之后)。

请参阅教程:http ://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

永远不要创建新线程并从 Swing EDT 运行它

于 2012-06-25T08:41:34.817 回答
4

看看这个:http: //javarevisited.blogspot.ro/2012/02/what-is-blocking-methods-in-java-and.html

1) 如果您正在编写 GUI 应用程序,则可能在 Swing 中永远不会在事件调度程序线程或事件处理程序中调用阻塞方法。例如,如果您在单击按钮时正在读取文件或打开网络连接,请不要在 actionPerformed() 方法上执行此操作,而只需创建另一个工作线程来完成该工作并从 actionPerformed() 返回。这将使您的 GUI 保持响应,但是如果操作需要用户等待而不是考虑使用 invokeAndWait() 进行同步更新,这又取决于设计。

使用多个线程:http: //javarevisited.blogspot.ro/2011/02/how-to-implement-thread-in-java.html

于 2012-06-25T08:08:23.110 回答
3

您将需要使用多线程。如果我在哪里,我会将 GUI 代码和服务器代码分开,当按下按钮时,我只需将服务器代码作为新线程启动。

您的代码基本上冻结了 GUI,因为所有事件都在事件调度程序线程 (EDT) 上执行,该线程负责处理所有 GUI 内容和相应的事件。如果您阻止它,停止它或抛出循环,它将影响其性能。

于 2012-06-25T08:03:46.317 回答
2

试试这些...

1. During getting the initial connection delay can occur, so first create and empty socket,then try to connect to the server.

   `Socket s = new Socket();`

   `s.connect(new InetSocketAddress("ip_addr",port_nos),1000);`

2. And Secondly always keep the Non-UI work out of Your UI thread..

这是我的服务器示例-客户端通信..

客户端代码:

public class ClientWala {

    public static void main(String[] args) throws Exception{

        Boolean b = true;
    Socket s = new Socket();
    s.connect(new InetSocketAddress("127.0.0.1", 4444),1000);

    System.out.println("connected: "+s.isConnected());


    OutputStream output = s.getOutputStream();
    PrintWriter pw = new PrintWriter(output,true);

    // to write data to server
    while(b){

        if (!b){

             System.exit(0);
        }

        else {
            pw.write(new Scanner(System.in).nextLine());
        }
    }


    // to read data from server
    InputStream input   = s.getInputStream();
    InputStreamReader isr = new InputStreamReader(input);
    BufferedReader br = new BufferedReader(isr);
    String data = null;

    while ((data = br.readLine())!=null){

        // Print it using sysout, or do whatever you want with the incoming data from server

    }




    }
}

服务器端代码:

import java.io.*
import java.net.*;


public class ServerTest {

    ServerSocket s;

    public void go() {

        try {
            s = new ServerSocket(44457);

            while (true) {

                Socket incoming = s.accept();
                Thread t = new Thread(new MyCon(incoming));
                t.start();
            }
        } catch (IOException e) {

            e.printStackTrace();
        }

    }

    class MyCon implements Runnable {

        Socket incoming;

        public MyCon(Socket incoming) {

            this.incoming = incoming;
        }

        @Override
        public void run() {

            try {
                PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
                        true);
                InputStreamReader isr = new InputStreamReader(
                        incoming.getInputStream());
                BufferedReader br = new BufferedReader(isr);
                String inp = null;

                boolean isDone = true;

                System.out.println("TYPE : BYE");
                System.out.println();
                while (isDone && ((inp = br.readLine()) != null)) {

                    System.out.println(inp);
                    if (inp.trim().equals("BYE")) {
                        System.out
                                .println("THANKS FOR CONNECTING...Bye for now");
                        isDone = false;
                        s.close();
                    }

                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                try {
                    s.close();
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                e.printStackTrace();
            }

        }

    }

    public static void main(String[] args) {

        new ServerTest().go();

    }

}
于 2012-06-25T15:08:40.783 回答