【问题标题】:Client-Server - freezing button客户端-服务器 - 冻结按钮
【发布时间】:2015-12-10 20:22:56
【问题描述】:

我正在编写一个简单的客户端-服务器应用程序。它应该像那样工作。我运行服务器应用程序而不是单击按钮来创建服务器。当服务器打开时,我可以使用客户端应用程序并连接到服务器。服务器还具有弹出消息日志的 JTextFild tfLog。 我的问题是,当我单击按钮创建服务器时,如果冻结。 Image

一切看起来像这样:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class ServerGui extends JFrame implements ActionListener{

protected JButton bCreateServer;
public static JTextArea taLOg;

public ServerGui(){
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            dispose();
        }
    });
    initLayout();
    setVisible(true);


}

private void initLayout() {
    setSize(600, 400);
    setResizable(false);
    setLayout(null);
    Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
    this.setLocation(dimension.width/2-this.getSize().width/2,
            dimension.height/2 - this.getSize().height/2);

    bCreateServer = new JButton("Utwórz serwer");
    bCreateServer.setBounds(20,20,150,25);
    bCreateServer.addActionListener(this);
    bCreateServer.setActionCommand("Create");
    add(bCreateServer);

    taLOg = new JTextArea();
    taLOg.setEditable(false);
    JScrollPane pane = new JScrollPane(taLOg);
    pane.setBounds(20, 50, 400,300);
    add(pane);
}

public static void main(String args[]){
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            new ServerGui();
        }
    });
}

public void insertText(final String line){
    if(SwingUtilities.isEventDispatchThread()){
        taLOg.insert(line, 0);
    }
    else{
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run(){
                taLOg.insert(line, 0);
            }
        });
    }
}

@Override
public void actionPerformed(ActionEvent e) {

    String tmp = e.getActionCommand();
    if(tmp.equals("Create")){

        Server server = new Server(8080);
        if(server.serverCreated){
            insertText("Kliknięto Utwórz serwer\n");
            server.clientsListener();
        }
        else{
            insertText("Nie udało się utworzyć serwera\n");
        }

    }
}
}

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server{
private ServerSocket serverSocket;
private Socket socket;
public Boolean serverCreated = false;
public Server(int port){
    try{
        serverSocket = new ServerSocket(port);
    }
    catch(IOException e){
        System.out.println("Błąd przy tworzeniu gniazda serwerowego.");
        System.exit(-1);
    }
    serverCreated = true;
}
public void clientsListener(){
    try{
        socket = serverSocket.accept();
    }
    catch(IOException e){
        System.out.println(e);
    }

    System.out.println(socket);
    try{
        serverSocket.close();
    }
    catch(IOException e){
        System.out.println("Błąd przy zamykaniu gniazda serwerowego.");
        System.exit(-1);
    }
}
}


import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client{

Socket clientSocket;

public Client(String hostname, int port){
    try{
        clientSocket = new Socket(hostname, port);
    }
    catch(UnknownHostException e){
        System.out.println("Nieznany host.");
    }
    catch(IOException e){
        System.out.println(e);
        System.exit(-1);
    }
    System.out.println(clientSocket);
}

public static void main(String args[]){
    Client client = new Client("localhost", 8080);
}
}

【问题讨论】:

    标签: java swing client-server


    【解决方案1】:

    您的 actionPerformed 处理程序(在应用程序的主 UI 线程上执行)调用服务器对象上的 clientsListen(),然后调用 .accept()。 accept() 将阻塞,直到客户端连接。这就是您的 GUI 挂起的原因。

    您需要创建一个新线程来为您的服务器执行代码。
    actionPerformed 中的类似内容:

    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
           Server server = new Server(8080);
           if(server.serverCreated){
              server.clientsListener();
           }
        }
    });
    
    t.setDaemon(true);
    t.start();
    

    让客户端启动服务器也有点奇怪。作为一个实验,我可以理解它,但如果你让客户端能够启动服务器,你可能应该给他们一种停止它的方法。这将涉及线程之间的某种 IPC,这可能会偏离您的简单概念。

    【讨论】:

    • 新线程解决了我的问题,但我不明白是客户端启动服务器吗?这将是扑克游戏,多个客户端可以连接到服务器,但现在我正在测试解决方案。
    • 您的服务器代码现在需要在每次客户端连接时启动一个新线程。在 google 上搜索简单的 java 服务器示例,您就会明白我的意思。顺便说一句,如果我的回答或任何其他在这里证明有帮助,请将其标记为已接受。
    • @Slovvik 还要注意 Swing 不是线程安全的,因此您对 UI 所做的任何修改都必须在事件调度线程的上下文中完成。请参阅Concurrency in Swing 了解更多详情
    猜你喜欢
    • 1970-01-01
    • 2017-02-26
    • 2016-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多