Java Socket冻结问题

时间:2013-09-27 06:18:26

标签: java sockets

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

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调用它时,我的整个程序冻结了。这里的问题在哪里,我该如何解决?

P.S。这是我的服务器代码(以防万一)

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

1 个答案:

答案 0 :(得分:1)

  1. 以这种方式使用static引用是一个非常糟糕的设计。您冒着不确切知道引用内容的风险。
  2. Swing是单线程环境,也就是说,所有对UI的交互和修改都应该在事件调度线程的上下文中执行。任何阻止此线程的操作,比如阻塞I / O或长时间运行的循环,都会阻止UI处理新事件和绘制请求。
  3. 到目前为止,你已经基本上把它搞砸了。当{J}运行main时,它正在运行,通常称为“主”线程。当您开始使用任何Swing组件时,Swing API将启动“事件调度线程”...

    所以发生了什么,你正在启动你的应用程序的UI部分,它的上下文正在转移到EDT,而run方法p2继续在{{1}中运行} thread。

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

    现在,你有两个问题。首先,你需要将你的通信从EDT中删除,你的第二个是,你不应该从EDT以外的任何线程修改或更新UI ...

    您可以使用多种解决方案,main可能是最简单的问题。

    请查看Concurrency in Swing了解详情