0

我举了一个例子来说明我希望我的程序是什么。问题是我无法使我的套接字连接正常工作(我希望它工作的方式)。而且我不知道问题出在哪里。

public class TestChat extends Frame {

public static Panel1 p1;
public static Panel2 p2;
public static TestChat tc;

public TestChat() {
    super();
    setPreferredSize(new Dimension(800, 600));
    setLayout(new BorderLayout());
    addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent we) {
            System.exit(0);
        }
    });

    p1 = new Panel1();
    p2 = new Panel2();
    add(p1);
}

public static void main(String[] args) {
    // TODO code application logic here
    tc = new TestChat();
    tc.pack();
    tc.setVisible(true);
    ///*
    try {
        TestChat.p2.run();
    } catch (IOException ioe) {
        System.out.println("IO here");
    }
    //*/
}

public void change(int to) {
    if (to == 1) {
        tc.remove(p2);
        tc.add(p1);
    }
    if (to == 2) {
        tc.remove(p1);
        tc.add(p2);
    }
    tc.pack();
}
}

public class Panel1 extends Panel implements ActionListener{

public Button button = new Button("Launch chat");

public Panel1() {
    super();
    setLayout(new BorderLayout());
    Label label = new Label("Launcher panel here");
    add(label);
    add(button, BorderLayout.SOUTH);
    button.addActionListener(this);
}

@Override
public void actionPerformed(ActionEvent e) {
    if (e.getSource() == button) {
        TestChat.tc.change(2);
        /*
        try {
            TestChat.p2.run();
        } catch (IOException ioe) {
            System.out.println("IO here");
        }
        //*/
    }
}

}

public class Panel2 extends Panel implements ActionListener {

private static final int LOGIN_MAX = 300;
public static TextArea ta = new TextArea();
public static TextField tf = new TextField();
public static TextArea logins = new TextArea();
public static PrintWriter out = null;
public static String[] loginList = new String[LOGIN_MAX];
public static int loginCount = 0;
public Panel temp = new Panel();
public Button startButton = new Button("Start!");
///*
public String fromServer;
public BufferedReader in = null;
public BufferedReader stdIn;
public Socket kkSocket = null;
//*/

public Panel2() {
    setLayout(new BorderLayout());
    temp.setLayout(new BorderLayout());
    ta.setEditable(false);
    tf.addActionListener(this);
    startButton.addActionListener(this);
    logins.setEditable(false);
    temp.add(ta, BorderLayout.CENTER);
    temp.add(tf, BorderLayout.SOUTH);
    add(temp);
    add(logins, BorderLayout.EAST);
    add(startButton, BorderLayout.SOUTH);
}

//private static void makeLogins() {
public static void makeLogins() {
    String userArea = loginList[0] + "\n";
    for (int i = 1; i < loginCount; i++) {
        userArea = userArea + loginList[i] + "\n";
    }
    logins.setText(userArea);
}

public void run() throws IOException {

    kkSocket = null;

    BufferedReader in = null;

    try {
        kkSocket = new Socket("localhost", 4444);
        out = new PrintWriter(kkSocket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream()));
    } catch (UnknownHostException e) {
        //System.err.println("Can't host to server.");
        System.out.println("Can't host to server.");
        System.exit(1);
    } catch (IOException e) {
        System.err.println("Couldn't get I/O for the connection to server.");
        System.exit(1);
    }

    BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
    String fromServer;

    while ((fromServer = in.readLine()) != null) {
        validate();
        if (fromServer.startsWith("cmd_newUser_")) {
            loginList[loginCount++] = fromServer.substring(12);
            if (loginCount > 1) {
                Arrays.sort(loginList, 1, loginCount - 1);
            }
            makeLogins();
        } else if (fromServer.startsWith("cmd_deleteUser_")) {
            String tmp = fromServer.substring(15);
            for (int i = 0; i < loginCount; i++) {
                if (loginList[i].equals(tmp)) {
                    loginList[i] = "" + ((char) 255);
                    break;
                }
            }
            Arrays.sort(loginList, 1, loginCount);
            loginCount--;
            makeLogins();
        } else {
            ta.append(fromServer + "\n");
        }
        if (fromServer.equals("Bye.")) {
            break;
        }
    }

    out.close();
    in.close();
    stdIn.close();
}

private void sendStr(PrintWriter out) {
    if (tf.getText() != "") {
        out.println(tf.getText());
        tf.setText("");
    }
}

@Override
public void actionPerformed(ActionEvent e) {
    if (e.getSource() == tf) {
        sendStr(out);
    } else if (e.getSource() == startButton) {
        System.out.println("I make some actions in the original proj");
    }
}
}

当我以这种方式使用它时,我的程序会连接并且一切正常。但是我想在按下按钮时从 Panel1 类开始连接(注释调用)。当我尝试从 Panel1 调用它时,我的整个程序会冻结。这里的问题在哪里,我该如何解决?

PS这是我的服务器代码(以防万一)

public class KKMultiServer extends Frame {

public static int userCount = 0;
public static Label users;
public static KKMultiServerThread[] userList=new KKMultiServerThread[100];
public static int writer=0;
public static int curNum=1;

public KKMultiServer() {
    super("Server");
    setLayout(new GridLayout(2, 1));
    users = new Label("Users online: " + userCount);
    add(users);
    setLocation(200, 200);
    setResizable(false);
    setMinimumSize(new Dimension(300, 200));
    addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent we) {
            System.exit(0);
        }
    });
}

public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = null;
    boolean listening = true;
    KKMultiServer server = new KKMultiServer();
    server.pack();
    server.setVisible(true);

    try {
        serverSocket = new ServerSocket(4444);
    } catch (IOException e) {
        System.err.println("Could not listen on port: 4444.");
        System.exit(-1);
    }

    while (listening) {                             
        userList[writer]=new KKMultiServerThread(serverSocket.accept());
        System.out.println("Client added!");
        userCount++;
        users.setText("Users online: " + userCount);
        userList[writer++].start();         


    }

    serverSocket.close();
}
}
4

1 回答 1

1
  1. 以这种方式使用static引用是一个非常糟糕的设计。您冒着不确切知道您引用的内容的风险。
  2. Swing 是单线程环境,也就是说,对 UI 的所有交互和修改都应该在 Event Dispatching Thread 的上下文中执行。任何阻塞此线程的操作,例如阻塞 I/O 或长时间运行的循环,都会阻止 UI 处理新事件和绘制请求。

到目前为止,您基本上已经侥幸了。当main由 JVM 运行时,它正在运行,即通常所说的“主”线程。当您开始使用任何 Swing 组件时,Swing API 将启动“事件调度线程”...

那么发生了什么,您正在启动应用程序的 UI 部分,它的上下文被移至 EDT,而该run方法p2继续在main线程中运行。

现在您想从按钮开始通信,您已将执行上下文移动到 EDT,这使得您的应用程序看起来像挂起......

现在,你有两个问题。第一个是,您需要从 EDT 中获取通讯,第二个是,您永远不应该从 EDT 以外的任何线程修改或更新 UI...

有许多解决方案可供您使用,SwingWorker对于您的问题可能是最简单的。

查看Swing 中的并发以获取更多详细信息

于 2013-09-27T06:39:50.707 回答