Reputation: 13
I am making a simple 1v1 "private chat" using TCP in java. Currently, i have a problem whenever i am using JButtons. This is my first attempt at using JButtons and ActionListeners so i'm not 100% sure whats going on here.
I have two separate projects for the Server and the Client. To compile these, it would have to be two separate projects.
The problem occurs when i try to hit the button to either A: Start the server B: Connect to the server.
The button freezes as if it is in the pushed state. While running the server and hitting the button, to "unpress" the button, a client has to try and connect. The server sends out a MOTD to the client and the client should print that out onto the text window. It prints out the MOTD only once the server is closed. Again, not sure why
The server code:
package net.valid4life.chat;
import java.awt.Component;
public class Chat implements ActionListener {
private static final long serialVersionUID = 1L;
private static JFrame mainFrame;
private static JPanel contentPane;
private static JTextArea chatWindow;
private static JTextArea serverWindow;
private static JTextField chatBox;
private static JTextField portBox;
private static JLabel currentStatusL;
private static JLabel portl;
private static JLabel status;
private static JButton startServerButton;
private static int port = 1234;
public static final int NOT_STARTED = 0;
public static final int WAITING_FOR_CLIENT = 1;
public static final int CONNECTED = 2;
private static int currentStatus = NOT_STARTED;
public static String newLine = "\n";
public static boolean started = false;
static ServerSocket listener = null;
public static void initGUI() {
mainFrame = new JFrame("Chat Server");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
mainFrame.setContentPane(contentPane);
contentPane.setLayout(null);
chatWindow = new JTextArea();
chatWindow.setLineWrap(true);
chatWindow.setEditable(false);
chatWindow.setBounds(220, 15, 200, 215);
chatWindow.setAlignmentY(Component.BOTTOM_ALIGNMENT);
contentPane.add(chatWindow);
serverWindow = new JTextArea();
serverWindow.setLineWrap(true);
serverWindow.setEditable(false);
serverWindow.setBounds(10, 150, 201, 80);
contentPane.add(serverWindow);
chatBox = new JTextField();
chatBox.setBounds(221, 236, 199, 20);
contentPane.add(chatBox);
chatBox.setColumns(10);
portBox = new JTextField("1234");
portBox.setBounds(68, 37, 86, 25);
portBox.setActionCommand("portEnter");
portBox.setColumns(10);
contentPane.add(portBox);
portl = new JLabel("Port:");
portl.setFont(new Font("Times New Roman", Font.PLAIN, 16));
portl.setBounds(95, 20, 64, 14);
contentPane.add(portl);
status = new JLabel("Status:");
status.setFont(new Font("Times New Roman", Font.PLAIN, 16));
status.setBounds(15, 239, 46, 14);
contentPane.add(status);
currentStatusL = new JLabel(changeStatus(NOT_STARTED));
currentStatusL.setFont(new Font("Times New Roman", Font.PLAIN, 16));
currentStatusL.setBounds(60, 239, 151, 14);
contentPane.add(currentStatusL);
startServerButton = new JButton("Start Server");
startServerButton.setFont(new Font("Times New Roman", Font.PLAIN, 13));
startServerButton.setBounds(60, 96, 100, 40);
startServerButton.setActionCommand("start");
startServerButton.addActionListener(new Chat());
contentPane.add(startServerButton);
mainFrame.setVisible(true);
}
public static void main(String[] args) throws IOException {
initGUI();
}
public void actionPerformed(ActionEvent e) {
if ("start".equals(e.getActionCommand())) {
try {
port = Integer.parseInt(portBox.getText());
startServerButton.setEnabled(false);
listener = new ServerSocket(port);
changeStatus(WAITING_FOR_CLIENT);
serverWindow.append("The server has started on "
+ listener.getLocalPort());
} catch (IOException e1) {
e1.printStackTrace();
} finally {
try {
startServer();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}else
System.out.println("YOU BROKE IT");
}
public static void startServer() throws IOException {
try {
System.out.println("Looking for client");
new ServerThread(listener.accept()).start();
System.out.println("Found client");
} catch (Exception e) {
e.printStackTrace();
} finally {
listener.close();
}
}
public static String changeStatus(int newStatus) {
String newStatusText;
switch (newStatus) {
case 0:
newStatusText = "Server not started.";
break;
case 1:
newStatusText = "Waiting for client.";
break;
case 2:
newStatusText = "Connected to client.";
break;
default:
newStatusText = "Broken";
}
currentStatus = newStatus;
return newStatusText;
}
public static class ServerThread extends Thread {
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
Chat.serverWindow.append("New Connection from:"
+ socket.getInetAddress() + Chat.newLine);
Chat.changeStatus(CONNECTED);
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(),
true);
out.println("MOTD:Welcome to the testing phase of this chat!");
out.println("To view commands simply type /help");
while (true) {
String input = in.readLine();
if (input == null || input.equals(".")) {
break;
}
out.println(input);
}
} catch (IOException e) {
Chat.serverWindow.append("Error handling client");
} finally {
try {
socket.close();
} catch (IOException e) {
Chat.serverWindow
.append("Couldn't close a socket, what's going on?");
}
Chat.serverWindow.append("Connection with client closed");
}
}
}
}
The client code:
package net.valid4life.chat;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class Chat implements ActionListener {
private static JFrame mainFrame;
private static JPanel contentPane;
private static JTextArea chatWindow;
private static JTextField chatBox;
private static JTextField portBox;
private static JLabel currentStatusL;
private static JLabel portl;
private static JLabel status;
private static JButton connectButton;
private static int port = 1234;
private static String hostIP = "127.0.0.1";
public static final int NOT_STARTED = 0;
public static final int WAITING_FOR_SERVER = 1;
public static final int CONNECTED = 2;
private static int currentStatus = NOT_STARTED;
public static boolean serverStarted = false;
private static JTextField IPField;
private static JLabel IPL;
private static BufferedReader in;
private static PrintWriter out;
public static void initGUI() {
public static void connectToServer() throws Exception {
port = Integer.parseInt(portBox.getText());
hostIP = IPField.getText();
Socket socket = new Socket("127.0.0.1", 1234);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
for (int i = 0; i < 3; i++) {
chatWindow.append(in.readLine() + "\n");
}
// connectButton.setEnabled(false);
}
public static void main(String[] args) throws Exception {
initGUI();
connectToServer();
}
public void actionPerformed(ActionEvent e) {
if ("start".equals(e.getActionCommand())) {
try {
connectToServer();
} catch (Exception e1) {
e1.printStackTrace();
}
} else {System.out.println("ASDASD");}
}
public static String changeStatus(int newStatus) {
String newStatusText;
switch (newStatus) {
case 0:
newStatusText = "Server not started.";
break;
case 1:
newStatusText = "Waiting for client.";
break;
case 2:
newStatusText = "Connected to client.";
break;
default:
newStatusText = "Broken";
}
currentStatus = newStatus;
return newStatusText;
}
}
Thanks in advance for the help!
Upvotes: 0
Views: 1946
Reputation: 347194
Your server code runs well, but your client is blocking the Event Dispatching Thread when you call connectToServer
.
The Event Dispatching Thread is responsible for, amongst other things, processing repaint requests and new input events. If you block this thread for any reasons, then there is no way that the Event Dispatching Thread can process any new events...
All blocking or long running tasks should be executed out side of the context of the Event Dispatching Thread.
Take a look at Concurrency in Swing for more details
Upvotes: 1