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!
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
Related
I would like to implement a frame where you can press a button to make a call, and then either the respondent, the manager or the director would respond to the call, and it would output on the screen who answered the call.
If an employee is not available, I would like to show on the console. So for example if respondent and manager are not available, I would like the output to look like this:
Respondent busy. Forwarding to manager.
Manager busy. Forwarding to Director.
Director answered the call.
With my implementations these messages are shown, but they are all showed instantly. I would like to set some waiting time between the messages, like:
shows message: "Manager is busy. Forwarding to director"
waits 2 seconds
shows message: "Director answered the call"
CallHandler.java:
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class CallHandler implements Runnable{
private ArrayList<Employee> employees = new ArrayList<>();
private MyFrame view;
public CallHandler(){
employees.add(new Respondent());
employees.add(new Manager());
employees.add(new Director());
view = new MyFrame(this);
}
public void dispatchCall() throws InterruptedException {
boolean dialing = true;
while(dialing) {
for (Employee employee : getAvailableEmployees()) {
Status status = employee.call();
if (status == Status.ANSWERED) {
(new Thread(employee)).start();
sendMessage(employee.getClass().getName() + " has answered the call.");
dialing = false;
break;
}
sendMessage(employee.getClass().getName() + " is busy. You will be redirected to the next available employee.");
}
if (dialing)
sendMessage("No one is available at the moment. Please wait...");
}
}
private void sendMessage(String msg) throws InterruptedException {
view.addMessage(msg);
}
private ArrayList<Employee> getAvailableEmployees(){
return employees.stream().filter(Employee::isFree).collect(Collectors.toCollection(ArrayList::new));
}
public static void main(String args[]){
CallHandler handler = new CallHandler();
}
#Override
public void run() {
try{
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
} catch (InterruptedException e) {
System.out.println("Call got interrupted");
}
}
}
MyFrame.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
public class MyFrame extends JFrame implements Runnable {
private static final int WIDTH = 800;
private static final int HEIGHT = 500;
private static final int PANEL_WIDTH = 600;
private static final int PANEL_HEIGHT = 290;
private final JPanel panel = new JPanel();
private final ArrayList<JLabel> labels = new ArrayList<>();
private int rowIndex = 0;
private static final int ROWS = 17;
private CallHandler handler = null;
private Timer timer;
MyFrame(CallHandler callHandler) {
handler = callHandler;
this.setLayout(null);
setVisible(true);
setSize(WIDTH, HEIGHT);
add(panel);
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
panel.setBackground(Color.GREEN);
panel.setBounds(100, 50, PANEL_WIDTH, PANEL_HEIGHT);
JButton btn = new JButton("Make call");
btn.setBounds(350, 370, 100, 80);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
handler.dispatchCall();
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
});
this.add(btn);
initiateRows();
}
public void addMessage(String msg) throws InterruptedException {
if (rowIndex < ROWS) {
getLabel(rowIndex).setText(msg);
rowIndex++;
} else {
System.out.println("removing first component");
removeComponent(0);
addRow(msg);
}
panel.updateUI();
// Thread.sleep(1000);
}
private void initiateRows() {
for (int i = 0; i < ROWS; i++) {
addRow("");
}
}
private void addRow(String msg) {
JLabel label = new JLabel(msg);
label.setAlignmentX(Component.CENTER_ALIGNMENT);
labels.add(label);
panel.add(label);
}
private JLabel getLabel(int i) {
return (JLabel) panel.getComponent(i);
}
private void removeComponent(int i) {
panel.remove(i);
}
public static void main(String args[]) {
MyFrame f = new MyFrame(new CallHandler());
}
#Override
public void run() {
try{
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
} catch (InterruptedException e) {
System.out.println("Call got interrupted");
}
}
}
I'm having this problem where the thread that is used to get information from the client will not shutdown when that user has disconnected. The cpu usage goes up go to 100% and the program gets stuck in an infinite loop.
The problem is on the server side but I have searched and searched and I have found no way to solve this issue. I will post the whole server and client class but i think the issue is centered around the Transfer thread and the SendToAll method.
SERVER:
package serverSide;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server implements Runnable{
public final static int Port = 3000;
public static ServerSocket ss;
public static ArrayList<ClientInfo> Client;
public static String Message = "";
public static void main(String[] args) throws IOException {
#SuppressWarnings("unused")
Server server = new Server();
}
public Server() throws IOException{
ss = new ServerSocket(Port);
Client = new ArrayList<ClientInfo>();
new Thread(this).start();
}
public void run(){
try {
while (true){
//Accept new client
Socket s = ss.accept();
//Get client info
DataInputStream dis = new DataInputStream(s.getInputStream());
String Name = dis.readUTF();
//Give client storage
int Result = CheckClients();
if (Result == -1){
Result = Client.size();
Client.add(new ClientInfo(Name,Result,s));
} else {
Client.set(Result, new ClientInfo(Name,Result,s));
}
//Run get input
Transfer transfer = new Transfer(Client.get(Result).ClientID);
transfer.start();
}
} catch (IOException e) {
System.out.println("Connection Error");
}
}
public static void SendToAll() throws IOException{
for (int i=0;i<Client.size();i++){
DataOutputStream dos = new DataOutputStream(Client.get(i).ClientSocket.getOutputStream());
dos.writeUTF(Message);
}
Message = "";
}
public int CheckClients(){
int Result = -1;
for(int i = 0;i < Client.size() + 1;i++){
try{
if (Client.get(i) == null){
Result = i;
break;
}
} catch (IndexOutOfBoundsException e){
break;
}
}
return Result;
}
}
class Transfer extends Thread{
int ClientNumber;
public Transfer(int ClientNumber){
this.ClientNumber = ClientNumber;
}
public void run(){
while(true){
DataInputStream dis;
try {
dis = new DataInputStream(Server.Client.get(ClientNumber).ClientSocket.getInputStream());
String FromClient = dis.readUTF();
Server.Message = FromClient;
System.out.println(Server.Message);
Server.SendToAll();
} catch (IOException e) {
try {
this.join();
} catch (InterruptedException e1) {
}
break;
}
}
}
}
class ClientInfo {
public ClientInfo(String Name,int ClientID,Socket ClientSocket){
this.Name = Name;
this.ClientID = ClientID;
this.ClientSocket = ClientSocket;
}
public String Name;
public int ClientID;
public Socket ClientSocket;
}
CLIENT:
package clientSide;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.Window.Type;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import java.awt.Font;
import javax.swing.SwingConstants;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JLabel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class ClientWindow {
private JFrame frmClient;
private JTextArea txtLog;
private JTextField txtMessage;
public String ServerAddress;
public String Name;
public String Password;
public Socket s;
public final int Port = 3000;
public static void main(String[] args,String sa,String n,String p) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientWindow window = new ClientWindow(sa,n,p);
window.frmClient.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void ConnectToServer(JTextArea txtLog){
try {
s = new Socket(ServerAddress,Port);
System.out.println("Connected");
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF(Name);
GetResponse gr = new GetResponse(txtLog,s);
gr.start();
} catch (UnknownHostException e) {
JOptionPane.showMessageDialog(this.frmClient,"Unable to open connection to " + ServerAddress + ". Unknown host.","Error" ,JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
} catch (IOException e) {
JOptionPane.showMessageDialog(this.frmClient,"Unable to open connection to " + ServerAddress + ". Unknown host.","Error" ,JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}
public ClientWindow(String sa,String n,String p) throws InterruptedException {
ServerAddress = sa;
Name = n;
Password = p;
initialize();
}
private void initialize() {
frmClient = new JFrame();
frmClient.setResizable(false);
frmClient.setIconImage(Toolkit.getDefaultToolkit().getImage("C:\\Users\\joshu.DESKTOP-ECFG8JL\\workspace\\ChatSocket\\res\\icons\\Custom-Icon-Design-Flatastic-11-Connection.ico"));
frmClient.setType(Type.POPUP);
frmClient.setTitle("Connect");
frmClient.getContentPane().setBackground(new Color(15, 80, 120));
frmClient.setBounds(100, 100, 870, 650);
frmClient.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmClient.getContentPane().setLayout(null);
txtLog = new JTextArea();
txtLog.setEditable(false);
txtLog.setForeground(Color.WHITE);
txtLog.setFont(new Font("Calibri Light", Font.PLAIN, 24));
txtLog.setColumns(1);
txtLog.setBorder(new LineBorder(new Color(0, 153, 255)));
txtLog.setBackground(new Color(15, 80, 120));
txtLog.setBounds(7, 87, 845, 450);
frmClient.getContentPane().add(txtLog);
txtMessage = new JTextField();
txtMessage.setHorizontalAlignment(SwingConstants.LEFT);
txtMessage.setForeground(Color.WHITE);
txtMessage.setFont(new Font("Calibri Light", Font.PLAIN, 24));
txtMessage.setColumns(1);
txtMessage.setBorder(new LineBorder(new Color(0, 153, 255)));
txtMessage.setBackground(new Color(15, 80, 120));
txtMessage.setBounds(7, 559, 659, 40);
frmClient.getContentPane().add(txtMessage);
JButton btnSend = new JButton("Send");
btnSend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DataOutputStream dos;
try {
dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF(Name + ": " + txtMessage.getText());
txtMessage.setText("");
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
btnSend.setForeground(Color.WHITE);
btnSend.setFont(new Font("Calibri Light", Font.BOLD, 25));
btnSend.setBackground(new Color(51, 153, 204));
btnSend.setBounds(676, 559, 176, 40);
Border emptyBorder = BorderFactory.createEmptyBorder();
btnSend.setBorder(emptyBorder);
frmClient.getContentPane().add(btnSend);
JPanel panel = new JPanel();
panel.setLayout(null);
panel.setBackground(new Color(51, 153, 204));
panel.setBounds(0, 0, 864, 75);
frmClient.getContentPane().add(panel);
JLabel lblIP = new JLabel("Connected to: " + ServerAddress);
lblIP.setVerticalAlignment(SwingConstants.TOP);
lblIP.setHorizontalAlignment(SwingConstants.LEFT);
lblIP.setForeground(new Color(15, 80, 120));
lblIP.setFont(new Font("Calibri Light", Font.BOLD, 40));
lblIP.setBounds(12, 12, 853, 50);
panel.add(lblIP);
ConnectToServer(txtLog);
}
}
class GetResponse extends Thread{
JTextArea txtLog;
Socket s;
public GetResponse(JTextArea txtLog,Socket s){
this.txtLog = txtLog;
this.s = s;
}
public void run(){
while(true){
try {
DataInputStream dis = new DataInputStream(s.getInputStream());
String Input = dis.readUTF();
txtLog.setText(txtLog.getText() + "\n" + Input);
} catch (IOException e) {
}
}
}
}
So I've been working on this program off and on for a few days, its a basic client server chat room. I'm trying to have it so that when you launch the client, the gui that pops up has text inside of the portnumber, servername, and textbox JTextFields. Yesterday this was the case but I've changed things and now the gui appears without text in the text fields. That code is in the displaysettings method which runs at the beginning of the try catch block. Anyone know why it isn't working?
import java.net.*;
import java.util.*;
import java.io.*;
import java.awt.event.*;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class clienttry2 extends JFrame implements ActionListener {
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JPanel panel3 = new JPanel();
JButton send = new JButton("Send");
JButton connect = new JButton("Connect");
JLabel server = new JLabel("Server");
JLabel port = new JLabel("Port");
JButton disconnect = new JButton("Disconnect");
static JTextField servername = new JTextField(10);
static JTextField portnumber = new JTextField(10);
static JTextField textbox = new JTextField(40);
JTextArea chatbox = new JTextArea(20,45);
static Boolean isconnected = false;
static Boolean sending = false;
static Socket server1;
static ObjectInputStream in;
static ObjectOutputStream out;
public clienttry2(){
setTitle("Chat Room");
setLayout(new java.awt.FlowLayout());
setSize(600,500);
panel1.add(chatbox); //has all the chats
panel2.add(textbox); //area to type new messages into
panel2.add(send); send.addActionListener(this);//send button
panel3.add(server);
panel3.add(servername);
panel3.add(port);
panel3.add(portnumber);
panel3.add(connect); connect.addActionListener(this);
panel3.add(disconnect); disconnect.addActionListener(this); disconnect.setEnabled(false);
add(panel1);
add(panel2);
add(panel3);
}
public static void main(String[] args)throws Exception {
Client display = new Client();
display.setVisible(true);
try{
displaysettings();
connect();
setup();
String message;
message = (String) in.readObject();
System.out.println(message);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
private static void displaysettings() {
portnumber.setText("3333");
servername.setText("localhost");
textbox.setText("This is where you type your messages to send to others on the server!");
}
private static void connect() throws UnknownHostException, IOException {
server1 = new Socket("localhost", 3333);
}
private static void setup() throws IOException {
out = new ObjectOutputStream(server1.getOutputStream());
out.flush();
in = new ObjectInputStream(server1.getInputStream());
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==connect)
{
System.out.println("connected");
isconnected = true;
connect.setEnabled(false);
disconnect.setEnabled(true);
}
if(e.getSource()==send)
{
System.out.println("sending chat");
sending = true;
}
if(e.getSource()==disconnect)
{
try {
server1.close();
out.close();
isconnected = false;
connect.setEnabled(true);
disconnect.setEnabled(false);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
Swing components will not update unless told to. After you set the text, call:
textbox.repaint();
to force the GUI to update.
I have a multi-thread chatroom that connects to one server. They all connect, login, and message independently of each other just fine, but when I log off with one of the clients (and the server does a socket.close() for that instance of the client) all clients are logged off. I looked at a bunch of other questions on stackoverflow before posting this, but none of them had the same issue as mine (that I found). Note: All the clients were running locally on my computer, 2+ of them, and that's how I encountered the bug. Could them being on the same IP (though everything is done on my localhost..) cause this to happen? Any help or insight as to what is causing this issue and how I could resolve it would be great. When the issue occurs it also outputs this to the console:
Socket: Socket[addr=localhost/127.0.0.1,port=4000,localport=55650]
Here is the code (how to recreate the bug is at the bottom):
Server class:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;
public class ChatServer {
private static final int PORT = 4000;
private static HashSet<String> names = new HashSet<String>();
private static HashSet<ObjectOutputStream> outputs =
new HashSet<ObjectOutputStream>();
public static void main(String[] args) throws IOException{
System.out.println("The chat server is running...");
ServerSocket listener = new ServerSocket(PORT);
while(true){
new Handler(listener.accept()).start();
}
}
private static class Handler extends Thread{
private String name;
private Socket socket;
private ObjectInputStream in;
private ObjectOutputStream out;
private boolean loggedOut;
public Handler(Socket socket){
this.socket = socket;
}
public void run(){
try {
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
loggedOut = false;
while(true){
Message message = (Message) in.readObject();
System.out.println("Server recieved login message!");
if(message.getNumber() == 0){
name = message.getName();
synchronized(names){
if(!names.contains(name)){
names.add(name);
break;
}else{
Message nameTaken = new Message(null, 3);
sendMessage(out, nameTaken);
}
}
}
}
synchronized(outputs){
outputs.add(out);
}
for(ObjectOutputStream output: outputs){
Message response = new Message(name, name + " has logged on.", 0);
sendMessage(output, response);
}
while(true){
System.out.println("Waiting for message...");
Message message = (Message) in.readObject();
Message response = null;
if(message.getNumber() == 1 && message.getMessage() != null){
response = new Message(message.getName(),
message.getMessage(), 1);
}else if(message.getNumber() == 2){
response = new Message(message.getName(), message.getName() +
" has logged off.", 2);
loggedOut = true;
}
for(ObjectOutputStream output: outputs){
sendMessage(output, response);
}
if(loggedOut) break;
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
if(name != null) names.remove(name);
if(out != null) outputs.remove(out);
try{
socket.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
private void sendMessage(ObjectOutputStream out, Message message){
ObjectOutputStream outPutMessage = out;
Message response = message;
try {
outPutMessage.writeObject(response);
outPutMessage.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
Client class:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ChatClient extends JFrame {
private JTextField inputField;
private JTextField nameField;
private JTextArea textArea;
private JButton loginButton;
private JButton logoutButton;
private JButton connectButton;
private JScrollPane textScroll;
private JScrollPane listScroll;
private JPanel textPanel;
private JPanel connectPanel;
private JPanel listPanel;
private JPanel inputPanel;
private JPanel namePanel;
private JPanel inputAndDisplayPanel;
private JPanel listAndLogoutPanel;
private ArrayList<String> stringList;
private JList list;
private final int CELL_WIDTH = 100;
private ObjectOutputStream out;
private ObjectInputStream in;
private JFrame chatFrame;
private ChatClient client;
private String name;
private final int PORT = 4000;
private boolean needServerData;
private boolean loggedIn;
private boolean previouslyLoggedIn;
private String serverAddress = null;
private Socket socket = null;
private void run() throws IOException, ClassNotFoundException{
needServerData = true;
loggedIn = true;
while(true){
//Loops before a user is logged in, verifies that the host is usable
while (socket == null) {
if (needServerData) {
try {
connectButton.setEnabled(false);
serverAddress = JOptionPane.showInputDialog(client,
"Enter server address: ", "Server Address",
JOptionPane.QUESTION_MESSAGE);
if(serverAddress == null){
JOptionPane.showMessageDialog(client,
"Click 'Connect' to re-enter server address.",
"Info", JOptionPane.PLAIN_MESSAGE);
needServerData = false;
connectButton.setEnabled(true);
}else if(serverAddress.equals("")){
JOptionPane.showMessageDialog(client,
"Invalid input! Enter a valid server address.",
"Error", JOptionPane.ERROR_MESSAGE);
}else {
socket = new Socket(serverAddress, PORT);
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
loginButton.setEnabled(true);
logoutButton.setEnabled(false);
nameField.setEnabled(true);
connectButton.setEnabled(false);
}
} catch (UnknownHostException e1) {
JOptionPane.showMessageDialog(client,
"Error: Unknown host!", "Error",
JOptionPane.ERROR_MESSAGE);
}
}
}
/*Loops after the user is logged in (will output to the textarea that that user logged in),
* reads in messages from server to append to the textarea and also determines if a user is
* logging out. Changes editable/enabled of buttons and text fields accordingly.
*/
if(loggedIn) {
Message message = (Message) in.readObject();
if (message.getNumber() == 1) {
textArea.append(message.getName() + ": "
+ message.getMessage() + "\n");
} else if (message.getNumber() == 0) {
inputField.setEditable(true);
textArea.append(message.getMessage() + "\n");
loginButton.setEnabled(false);
logoutButton.setEnabled(true);
} else if (message.getNumber() == 2) {
inputField.setText(null);
inputField.setEditable(false);
nameField.setText(null);
nameField.setEnabled(false);
connectButton.setEnabled(true);
logoutButton.setEnabled(false);
loggedIn = false;
previouslyLoggedIn = true;
textArea.append(message.getMessage() + "\n");
System.out.println("Socket: " + socket);
} else {
JOptionPane.showMessageDialog(client,
"Error: That name is taken!", "Error",
JOptionPane.ERROR_MESSAGE);
}
}
}
}
private String getServerAddress(){
return JOptionPane.showInputDialog(client, "Enter server address: ",
"Server Address", JOptionPane.QUESTION_MESSAGE);
}
public static void main(String[] args) throws IOException, ClassNotFoundException{
ChatClient client = new ChatClient();
try {
client.run();
} catch (IOException e) {
e.printStackTrace();
}
}
public ChatClient(){
//GUI Formatting Stuff
inputField = new JTextField(30);
nameField = new JTextField(10);
textArea = new JTextArea(25, 30);
loginButton = new JButton("Login");
logoutButton = new JButton("Logout");
connectButton = new JButton("Connect");
textScroll = new JScrollPane(textArea,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
textPanel = new JPanel();
listPanel = new JPanel();
inputPanel = new JPanel();
namePanel = new JPanel();
connectPanel = new JPanel();
textArea.setEditable(false);
textPanel.add(textScroll);
stringList = new ArrayList<String>();
list = new JList(stringList.toArray());
list.setFixedCellWidth(CELL_WIDTH);
listScroll = new JScrollPane(list);
listPanel.add(listScroll);
listAndLogoutPanel = new JPanel(new BorderLayout());
listAndLogoutPanel.add(listPanel, BorderLayout.CENTER);
listAndLogoutPanel.add(logoutButton, BorderLayout.SOUTH);
listAndLogoutPanel.add(loginButton, BorderLayout.NORTH);
inputField.setEditable(false);
inputPanel.add(inputField);
inputAndDisplayPanel = new JPanel(new BorderLayout());
inputAndDisplayPanel.add(textPanel, BorderLayout.CENTER);
inputAndDisplayPanel.add(inputPanel, BorderLayout.SOUTH);
nameField.setEnabled(false);
loginButton.setEnabled(false);
logoutButton.setEnabled(false);
namePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
namePanel.add(new JLabel("Name: "));
namePanel.add(nameField);
connectPanel.add(connectButton);
JPanel topPanel = new JPanel(new BorderLayout());
topPanel.add(namePanel, BorderLayout.WEST);
topPanel.add(connectPanel, BorderLayout.EAST);
JPanel centerPanel = new JPanel(new BorderLayout());
centerPanel.add(inputAndDisplayPanel, BorderLayout.CENTER);
centerPanel.add(topPanel, BorderLayout.NORTH);
JPanel eastPanel = new JPanel(new BorderLayout());
eastPanel.add(listAndLogoutPanel, BorderLayout.CENTER);
setLayout(new BorderLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
add(centerPanel, BorderLayout.CENTER);
add(eastPanel, BorderLayout.EAST);
pack();
setLocationRelativeTo(null);
//Listeners
loginButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
name = nameField.getText();
if(name.trim().length() < 3 || name.length() > 15 || name == null){
JOptionPane.showMessageDialog(client,
"Error: Name must be between 3 and 15 characters long.", "Error",
JOptionPane.ERROR_MESSAGE);
}else{
Message message = new Message(name, 0);
try {
out.writeObject(message);
out.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
loggedIn = true;
}
}
});
connectButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
needServerData = true;
if(previouslyLoggedIn) socket = null;
}
});
inputField.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
Message message = new Message(name, inputField.getText(), 1);
try {
out.writeObject(message);
out.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
inputField.setText(null);
}
});
logoutButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
Message message = new Message(name, 2);
try {
out.writeObject(message);
out.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
inputField.setText(null);
}
});
}
}
Message class:
import java.io.Serializable;
public class Message implements Serializable{
private int number;
private String message;
private String name;
public Message(String name, int number){
this.name = name;
this.number = number;
}
public Message(String name, String message, int number){
this.message = message;
this.number = number;
this.name = name;
}
public boolean isLogin(){
if(number == 0) return true;
return false;
}
public boolean isMessage(){
if(number == 1) return true;
return false;
}
public boolean isLogout(){
if(number == 2) return true;
return false;
}
public int getNumber() {
return number;
}
public String getMessage() {
return message;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I know this is a big block of code and not that neatly documented/formatted, so I apologize for that. I'm just posting the whole thing so you can duplicate the problem by running the code in it's entirety. Additionally, ignore the JList as I haven't gotten to that yet since I encountered and haven't been able to resolve the logging off/socket issue. To recreate the bug, go through the following steps:
Run the Server class
Run a client class, enter "localhost" as the server address, then enter a name and click log-in
Run another client class and follow step 2
Click log-off on one of the client classes, and you'll see the other is also logged off.
Thanks in advance for any help, I appreciate it!
In your ChatClient class, you need to change the line
} else if (message.getNumber() == 2) {
to
} else if (message.getNumber() == 2 && message.getName().equals(name)) {
Because the way it is currently, each chat client receives the message that a client has been logged out, and each client is responding to that by logging out. You will need to handle the additional case afterwards that message.getNumber() == 2, because as it stands now you will assume that it means the name was taken.
I have been working on an instant messenger in only java code for a while now. I am able to get it to work only if I am running the server and the client on the same computer then they communicate. But I cant get 2 different computers to connect to the same server and communicate. I have looked at many examples and I still dont understand what needs to be changed. I will show the code below most of it can be ignored only the network part needs to be looked at. The sever connection is at the bottom of the client code. I am a beginner and I appreciate any help. Thanks.
Client Code:
import javax.swing.*;
import javax.swing.text.DefaultCaret;
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.Date;
import java.net.*;
import java.io.*;
public class NukeChatv3 extends JFrame
{
private JTextArea showtext;
private JTextField usertext;
private String hostname;
private Socket connectionsock;
private BufferedReader serverinput;
private PrintWriter serveroutput;
private int port;
private static final long serialVersionUID = 1L;
private class entersend implements KeyListener
{
public void keyTyped ( KeyEvent e )
{
}
public void keyPressed ( KeyEvent e)
{
String text = usertext.getText();
if(e.getKeyCode()== KeyEvent.VK_ENTER)
{
if (usertext.getText().equals(""))
return;
else
{
//try{
serveroutput.println(text);
usertext.setText("");
//showtext.append("[" + ft.format(dNow) + "]" + "\n" + "UserName: " + serverdata +"\n\n");
//}
/*catch(IOException in)
{
showtext.append(in.getMessage());
}*/
}
}
else
return;
}
public void keyReleased ( KeyEvent e )
{
}
}
private class sender implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (usertext.getText().equals(""))
return;
else
{
Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("hh:mm:ss");
String text = usertext.getText();
usertext.setText("");
//* Send message to server
showtext.append(ft.format(dNow) + "\n" + "UserName: " + text +"\n\n");
}
}
}
private class startconnection implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
clientconnection connect = new clientconnection();
connect.start();
}
}
private class CheckOnExit implements WindowListener
{
public void windowOpened(WindowEvent e)
{}
public void windowClosing(WindowEvent e)
{
ConfirmWindow checkers = new ConfirmWindow( );
checkers.setVisible(true);
}
public void windowClosed(WindowEvent e)
{}
public void windowIconified(WindowEvent e)
{}
public void windowDeiconified(WindowEvent e)
{}
public void windowActivated(WindowEvent e)
{}
public void windowDeactivated(WindowEvent e)
{}
}
private class ConfirmWindow extends JFrame implements ActionListener
{
private static final long serialVersionUID = 1L;
public ConfirmWindow( )
{
setSize(200, 100);
getContentPane( ).setBackground(Color.LIGHT_GRAY);
setLayout(new BorderLayout( ));
JLabel confirmLabel = new JLabel(
"Are you sure you want to exit?");
add(confirmLabel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel( );
buttonPanel.setBackground(Color.GRAY);
buttonPanel.setLayout(new FlowLayout( ));
JButton exitButton = new JButton("Yes");
exitButton.addActionListener(this);
buttonPanel.add(exitButton);
JButton cancelButton = new JButton("No");
cancelButton.addActionListener(this);
buttonPanel.add(cancelButton);
add(buttonPanel, BorderLayout.SOUTH);
}
public void actionPerformed(ActionEvent e)
{
String actionCommand = e.getActionCommand( );
if (actionCommand.equals("Yes"))
System.exit(0);
else if (actionCommand.equals("No"))
dispose( );
else
System.out.println("Unexpected Error in Confirm Window.");
}
}
public static void main(String[] args)
{
NukeChatv3 nuke = new NukeChatv3();
nuke.setVisible(true);
}
public NukeChatv3()
{
setTitle("NukeChat v3");
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setSize(550, 400);
setResizable(false);
addWindowListener(new CheckOnExit());
addWindowListener(new WindowAdapter(){
public void windowOpened(WindowEvent e){
usertext.requestFocus();
}
});
getContentPane().setBackground(Color.BLACK);
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
showtext = new JTextArea(15, 35);
showtext.setEditable(false);
showtext.setLineWrap(true);
DefaultCaret caret = (DefaultCaret)showtext.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
JScrollPane scrollbar = new JScrollPane(showtext);
scrollbar.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollbar.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
c.anchor = GridBagConstraints.FIRST_LINE_START;
//c.gridwidth = 2;
c.insets = new Insets(20, 20, 20, 20);
c.weightx = .5;
c.weighty = .5;
c.gridx = 0;
c.gridy = 0;
add(scrollbar, c);
usertext = new JTextField(35);
usertext.requestFocusInWindow();
usertext.addKeyListener(new entersend());
//c.gridwidth = 1;
c.insets = new Insets(0, 20, 0, 0);
c.weightx = .5;
c.gridx = 0;
c.gridy = 1;
add(usertext, c);
JPanel empty = new JPanel();
c.gridx = 1;
c.gridy = 0;
empty.setLayout(new GridLayout(2,1));
JButton test1 = new JButton("test1");
empty.add(test1);
JButton test2 = new JButton("test2");
empty.add(test2);
add(empty, c);
JButton send = new JButton("Send");
send.addActionListener(new sender());
c.ipady = -5;
c.insets = new Insets(0, 0, 20, 0);
c.gridx = 1;
c.gridy = 1;
add(send, c);
JMenu menu = new JMenu("File");
JMenuItem connection = new JMenuItem("Connect");
connection.addActionListener(new startconnection());
menu.add(connection);
JMenuBar bar = new JMenuBar();
bar.add(menu);
setJMenuBar(bar);
}
private class clientconnection extends Thread
{
public void run()
{
try
{
// Set host name and port//
hostname = "localhost";
port = 16666;
// connect to socket of the server//
connectionsock = new Socket(hostname, port);
// set up client input from server//
serverinput = new BufferedReader(new InputStreamReader(connectionsock.getInputStream()));
// set up client output to server//
serveroutput = new PrintWriter(connectionsock.getOutputStream(), true);
// set up a looping thread to constantly check if server has sent anything
String serverdata = "";
while ((serverdata = serverinput.readLine()) != null)
{
Thread.sleep(500);
Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("hh:mm:ss");
showtext.append("[" + ft.format(dNow) + "]" + "\n" +"Recieved from server: \n" + "UserName: " + serverdata +"\n\n");
}
}
catch(IOException e)
{
System.out.println(e.getMessage());
}
catch(InterruptedException inter)
{
showtext.append("Unexpected interruption\n\n");
}
}
}
}
Server Code :
import java.net.ServerSocket;
import java.io.*;
import java.net.Socket;
import java.io.DataOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class servertest extends JFrame
{
private JButton start;
private JTextArea text;
private BufferedReader clientinput;
private PrintWriter clientoutput;
private class listen implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
connection connect = new connection();
connect.start();
}
}
public servertest ()
{
setSize(400,300);
setLayout(new BorderLayout());
start = new JButton("Start");
start.addActionListener(new listen());
add(start, BorderLayout.SOUTH);
text = new JTextArea(6, 10);
text.setEditable(false);
add(text, BorderLayout.CENTER);
}
private class connection extends Thread
{
public void run()
{
try
{
// Sets up a server socket with set port//
text.setText("Waiting for connection on port 16666");
ServerSocket serversock = new ServerSocket(16666);
// Waits for the Client to connect to the server//
Socket connectionsock = serversock.accept();
// Sets up Input from the Client to go to the server//
clientinput = new BufferedReader(new InputStreamReader(connectionsock.getInputStream()));
// Sets up data output to send data from server to client//
clientoutput = new PrintWriter(connectionsock.getOutputStream(), true);
// Test server to see if it can perform a simple task//
text.setText("Connection made, waiting to client to send there name");
clientoutput.println("Enter your name please.");
// Get users name//
String clienttext = clientinput.readLine();
// Reply back to the client//
String replytext = "Welcome " + clienttext;
clientoutput.println(replytext);
text.setText("Sent: " + replytext);
while ((replytext = clientinput.readLine()) != null)
{
clientoutput.println(replytext);
text.setText("Sent: " + replytext);
}
// If you need to close the Socket connections
// clientoutput.close();
// clientinput.close();
// connetionsock.close();
// serversock.close();
}
catch(IOException e)
{
System.out.println(e.getMessage());
}
}
}
public static void main(String[] args)
{
servertest test = new servertest();
test.setVisible(true);
}
In your client code, specify correct hostname/IP address where server is running:
private class clientconnection extends Thread
{
public void run()
{
try
{
// Set host name and port//
hostname = "localhost"; //<---- Change this to server IP address
port = 16666;