I have been following a tutorial on creating a GUI based chat room that uses multithreading. I want to add a keyword such as "\EXIT", so that when a user types it, they will be disconnected from the chatroom, with a message being sent to the chatroom saying that user has left. For example:
Ben: Hi
Katie: Hi
Ben: G2G
Ben: EXIT
Ben has left the chatroom
So far, I have this:
Server.java
//ChatServer.java
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.net.Socket;
public class ChatServer {
static ArrayList<String> userNames = new ArrayList<String>();
static ArrayList<PrintWriter> printWriters = new ArrayList<PrintWriter>();
public static void main(String[] args) throws Exception{
System.out.println("Press 1 for Console or 2 for GUI");
System.out.println("Waiting for clients...");
ServerSocket ss = new ServerSocket(14001);
while (true){
Socket soc = ss.accept();
System.out.println("Connection established");
ConversationHandler handler = new ConversationHandler(soc);
handler.start();
}
}
}
class ConversationHandler extends Thread
{
Socket socket;
BufferedReader in;
PrintWriter out;
String name;
PrintWriter pw;
static FileWriter fw;
static BufferedWriter bw;
public ConversationHandler(Socket socket) throws IOException {
this.socket = socket;
fw = new FileWriter("C:\\Users\\Abhay\\Desktop\\ChatServer-Logs.txt",true);
bw = new BufferedWriter(fw);
pw = new PrintWriter(bw,true);
}
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
int count = 0;
while (true){
if(count > 0){
out.println("NAMEALREADYEXISTS");
}
else{
out.println("NAMEREQUIRED");
}
name = in.readLine();
if (name == null){
return;
}
if (!ChatServer.userNames.contains(name)){
ChatServer.userNames.add(name);
break;
}
count++;
}
out.println("NAMEACCEPTED"+name);
ChatServer.printWriters.add(out);
while (true){
String message = in.readLine();
if (message.equals("EXIT")) {
pw.println(name + " has disconnected from the chat");
System.out.println(name + " has disconnected from the chat");
ChatServer.userNames.remove(name);
}
pw.println(name + ": " + message);
for (PrintWriter writer : ChatServer.printWriters) {
writer.println(name + ": " + message);
}
}
}
catch (Exception e){
System.out.println(e);
}
}
}
Client.Java
//ChatClient.java
import javax.swing.*;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;
public class ChatClient {
static JFrame chatWindow = new JFrame("Chat Application");
static JTextArea chatArea = new JTextArea(22, 40);
static JTextField textField = new JTextField(40);
static JLabel blankLabel = new JLabel(" ");
static JButton sendButton = new JButton("Send");
static BufferedReader in;
static PrintWriter out;
static JLabel nameLabel = new JLabel(" ");
ChatClient() {
chatWindow.setLayout(new FlowLayout());
chatWindow.add(nameLabel);
chatWindow.add(new JScrollPane(chatArea));
chatWindow.add(blankLabel);
chatWindow.add(textField);
chatWindow.add(sendButton);
chatWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
chatWindow.setSize(475, 500);
chatWindow.setVisible(true);
textField.setEditable(false);
chatArea.setEditable(false);
sendButton.addActionListener(new Listener());
textField.addActionListener(new Listener());
}
void startChat() throws Exception {
String ipAddress = JOptionPane.showInputDialog(
chatWindow,
"Enter IP Address:",
"IP Address is Required!",
JOptionPane.PLAIN_MESSAGE);
Socket soc = new Socket(ipAddress, 14001);
in = new BufferedReader(new InputStreamReader(soc.getInputStream()));
out = new PrintWriter(soc.getOutputStream(), true);
while (true){
String str = in.readLine();
if (str.equals("NAMEREQUIRED")){
String name = JOptionPane.showInputDialog(
chatWindow,
"Enter a unique name:",
"Name Required!!",
JOptionPane.PLAIN_MESSAGE);
out.println(name);
}
else if(str.equals("NAMEALREADYEXISTS")){
String name = JOptionPane.showInputDialog(
chatWindow,
"Enter another name:",
"Name Already Exits!!",
JOptionPane.WARNING_MESSAGE);
out.println(name);
}
else if (str.startsWith("NAMEACCEPTED")){
textField.setEditable(true);
nameLabel.setText("You are logged in as: "+str.substring(12));
}
else{
chatArea.append(str + "\n");
}
}
}
public static void main(String[] args) throws Exception {
ChatClient client = new ChatClient();
client.startChat();
}
}
class Listener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
ChatClient.out.println(ChatClient.textField.getText());
ChatClient.textField.setText("");
}
}
As you can see, in Server.java, I have used this IF statement.
if (message.equals("EXIT")) {
pw.println(name + " has disconnected from the chat");
System.out.println(name + " has disconnected from the chat");
ChatServer.userNames.remove(name);
}
However, when I run the program, the user does not get removed from the chat. Appreciate any tips of help!
It's not printing on the GUI because you're printing with the wrong PrintWriter
out is what prints to the GUI
pw prints to the file/console from what I can see.
Try
out.println(name + " has disconnected from the chat");
also, in order to exit the user from the chat and close the chat you should close the socket connection from the server end with a try{..} catch{..} finally{..} for the inputstream, outputstream and the socket, which you can then detect on the client end and close the client GUI.
Related
I am programming a simple multi-threaded client/server chat system. Project requirements specify: "Connection only happens when the connect button is clicked. The disconnect button should disconnect the connection. A user should be able to connect, disconnect, re-connect at will." Basically, I have the connect button hooked-up and running. However, when I attempt to disconnect I get stuck in an infinite loop where the client side (on command line) infinitely prints "Sock closed", while the server side infinitely prints "Message read: null". This has lead me to look into all of my for(;;) loops to somehow close the connections within them, however I cannot figure out how to close the connection within those loops. Please help, this is my first socket programming project and I am super stumped on this one! Thanks all.
Client:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
public class ClientFrame extends Frame{
public ClientFrame(){
setSize(500,500);
setTitle("Chat Client");
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent We){
System.exit(0);
}
});
add(new ClientPanel(), BorderLayout.CENTER);
setVisible(true);
}
public static void main(String[] args){
new ClientFrame();
}
} // end ClientFrame
class ClientPanel extends Panel implements ActionListener, Runnable{
TextField tf;
TextArea ta;
List list;
Button connect, disconnect;
Socket socketToServer;
PrintWriter pw;
BufferedReader br;
Thread t;
String userName;
public ClientPanel(){
setLayout(new BorderLayout());
tf = new TextField();
ta = new TextArea();
list = new List();
connect = new Button("Connect");
disconnect = new Button("Disconnect");
Panel bPanel = new Panel();
bPanel.add(connect);
disconnect.setEnabled(false);
bPanel.add(disconnect);
tf.addActionListener(this);
add(tf, BorderLayout.NORTH);
add(ta, BorderLayout.CENTER);
add(list, BorderLayout.EAST);
add(bPanel, BorderLayout.SOUTH);
connect.addActionListener(this);
disconnect.addActionListener(this);
} // end ClientPanel constructor
public void actionPerformed(ActionEvent ae){
if (ae.getSource() == tf){
String temp = tf.getText();
pw.println(userName+": "+temp);
tf.setText("");
} else if (ae.getSource() == connect){
if(tf.getText() == null || tf.getText().equals("")){
ta.append("Must enter a name to connect\n");
}else {
userName = tf.getText();
connect.setEnabled(false);
disconnect.setEnabled(true);
tf.setText("");
try{
socketToServer = new Socket("127.0.0.1", 3000);
pw = new PrintWriter(new OutputStreamWriter
(socketToServer.getOutputStream()), true);
br = new BufferedReader(new InputStreamReader
(socketToServer.getInputStream()));
}catch(UnknownHostException uhe){
System.out.println(uhe.getMessage());
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
}
t = new Thread(this);
t.start();
pw.println(userName);
pw.println(userName +" has entered the chat.");
}else if (ae.getSource()== disconnect){
try{
t.interrupt();
socketToServer.close();
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
}
} // end actionPerformed
public void run(){
for(;;){
try{
String temp = br.readLine();
ta.append(temp + "\n");
}catch(IOException ioe){
System.out.println(ioe.getMessage());
}
}
} // end run
} // end ClientPanel
Server:
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.awt.*;
public class ThreadedServerWithPresence{
public static void main(String[] args){
ArrayList<ThreadedHandlerWithPresence> handlers;
try{
handlers = new ArrayList<ThreadedHandlerWithPresence>();
ServerSocket s = new ServerSocket(3000);
for(;;){
Socket incoming = s.accept( );
new ThreadedHandlerWithPresence(incoming,
handlers).start();
}
}catch (Exception e){
System.out.println(e);
}
}
}
class ThreadedHandlerWithPresence extends Thread{
Socket incoming;
ArrayList<ThreadedHandlerWithPresence> handlers;
PrintWriter pw;
BufferedReader br;
String userName;
public ThreadedHandlerWithPresence(Socket i,
ArrayList<ThreadedHandlerWithPresence> handlers){
incoming = i;
this.handlers = handlers;
handlers.add(this);
}
public void setUserName(String userName){
this.userName = userName;
}
public String getUserName(){
return userName;
}
public void run(){
try{
br = new BufferedReader(new InputStreamReader
(incoming.getInputStream()));
pw = new PrintWriter(new OutputStreamWriter
(incoming.getOutputStream()),true);
String firstLine = br.readLine();
setUserName(firstLine);
for(;;){
String temp = br.readLine();
System.out.println("Message read: " + temp);
for(int i = 0; i < handlers.size(); i++){
handlers.get(i).pw.println(temp);
}
}
}catch (Exception e){
System.out.println(e);
}finally{
handlers.remove(this);
}
}
}
Client
Your run method does not handle interruptions so the for loop does not end and it continues trying to receive messages.
You must add an action that can be interrupted and throws InterruptedException, Thread.sleep would be a good candidate in this case, also reducing CPU usage (You do not need to check for new messages every single moment).
try {
for (; ; ) {
try {
String temp = br.readLine();
ta.append(temp + "\n");
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
}
Thread.sleep(10);
}
} catch (InterruptedException e) {
System.out.println("Disconnected.");
}
Server
When br.readLine() returns null, that indicates the connection is closed by the client and you should stop receiving messages.
String temp = br.readLine();
if(temp == null)
break;
so here is my code :
Server.java
import java.io.*;
import java.net.*;
import java.util.*;
class Server implements Runnable{
Socket connectionSocket;
public static Vector clients=new Vector();
public Server(Socket s){
try{
System.out.println("Client Got Connected " );
connectionSocket=s;
}catch(Exception e){e.printStackTrace();}
}
public void run(){
try{
BufferedReader reader =
new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
BufferedWriter writer=
new BufferedWriter(new OutputStreamWriter(connectionSocket.getOutputStream()));
clients.add(writer);
while(true){
String data1 = reader.readLine().trim();
System.out.println("Received : "+data1);
for (int i=0;i<clients.size();i++){
try{
BufferedWriter bw= (BufferedWriter)clients.get(i);
bw.write(data1);
bw.write("\r\n");
bw.flush();
}catch(Exception e){e.printStackTrace();}
}
}
}catch(Exception e){e.printStackTrace();}
}
public static void main(String argv[]) throws Exception{
System.out.println("Threaded Chat Server is Running " );
ServerSocket mysocket = new ServerSocket(5555);
while(true){
Socket sock = mysocket.accept();
Server server=new Server(sock);
Thread serverThread=new Thread(server);
serverThread.start();
}
}
}
mychat.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class mychat implements Runnable
{
public JTextField tx;
public JTextArea ta;
public String login="Imed";
BufferedWriter writer;
BufferedReader reader;
public mychat(String l)
{
login=l;
ClientName z = new ClientName();
JFrame f=new JFrame(z.getName()+"'s Chat");
f.setSize(400,400);
JPanel p1=new JPanel();
p1.setLayout(new BorderLayout());
JPanel p2=new JPanel();
p2.setLayout(new BorderLayout());
tx=new JTextField();
p1.add(tx, BorderLayout.CENTER);
JButton b1=new JButton("Send");
p1.add(b1, BorderLayout.EAST);
ta=new JTextArea();
p2.add(ta, BorderLayout.CENTER);
p2.add(p1, BorderLayout.SOUTH);
f.setContentPane(p2);
try
{
Socket socketClient= new Socket("localhost",5555);
writer= new BufferedWriter(new OutputStreamWriter(socketClient.getOutputStream()));
reader =new BufferedReader(new InputStreamReader(socketClient.getInputStream()));
}
catch(Exception e){e.printStackTrace();}
b1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ev)
{
String s=login+" : "+tx.getText();
tx.setText("");
try
{
writer.write(s);
writer.write("\r\n");
writer.flush();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
);
f.setVisible(true);
}
public void run()
{
try
{
String serverMsg="";
while((serverMsg = reader.readLine()) != null)
{
System.out.println("from server: " + serverMsg);
ta.append(serverMsg+"\n");
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
startclient.java
public class startclient
{
public static void main(String [] args)
{
try
{
ClientName n = new ClientName();
mychat c=new mychat(n.getName());
Thread t1=new Thread(c);
t1.start();
}
catch(Exception e){e.printStackTrace();}
}
}
And last ClientName.java
import java.util.*;
public class ClientName
{
String name;
public String getName()
{
Scanner sc = new Scanner(System.in);
System.out.print ("Enter your name : ");
name = sc.nextLine();
return name;
}
}
So basically, i want to limit how many client that could join my server(which maximum is 10 client). And if there is another client that want to join the server after it is full, that client will be rejected so it cannot joined.
I think that's it, though if there are any other improvement in other areas at my code it will also be appreciated. Sorry for my bad english
*Oh and sorry since I forget to include it, but somehow when I start the client, it ask the name twice
You can fix main method in your server and add sayGoodBye() as follows:
private static final int CONNECTION_LIMIT = 10;
public static void main(String argv[]) throws Exception {
System.out.println("Threaded Chat Server is Running ");
ServerSocket mysocket = new ServerSocket(5555);
int socketCount = 0;
while (true) {
Socket sock = mysocket.accept();
Server server = new Server(sock);
if (socketCount++ < CONNECTION_LIMIT) {
Thread serverThread = new Thread(server);
serverThread.start();
} else {
// without starting a thread and notifying only new client
server.sayGoodbye();
}
}
}
public void sayGoodbye() throws IOException {
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connectionSocket.getOutputStream()))) {
writer.write("Sorry, new client connections are not accepted, bye for now");
} catch (Exception e) {
e.printStackTrace();
}
connectionSocket.close();
}
Here is my code:
Server.java
import java.io.*;
import java.net.*;
import java.util.*;
class Server implements Runnable{
static int socketCount = 0;
Socket connectionSocket;
public static Vector clients=new Vector();
public Server(Socket s){
try{
System.out.println("Client Got Connected " );
connectionSocket=s;
}catch(Exception e){e.printStackTrace();}
}
public void run(){
try{
BufferedReader reader =
new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
BufferedWriter writer=
new BufferedWriter(new OutputStreamWriter(connectionSocket.getOutputStream()));
clients.add(writer);
while(true){
String data1 = reader.readLine().trim();
System.out.println("Received : "+data1);
for (int i=0;i<clients.size();i++){
try{
BufferedWriter bw= (BufferedWriter)clients.get(i);
bw.write(data1);
bw.write("\r\n");
bw.flush();
}catch(Exception e){e.printStackTrace();}
}
}
}catch(Exception e){e.printStackTrace();}
}
private static final int CONNECTION_LIMIT = 10;
public static void main(String argv[]) throws Exception {
System.out.println("Threaded Chat Server is Running ");
ServerSocket mysocket = new ServerSocket(5555);
while (true) {
Socket sock = mysocket.accept();
Server server = new Server(sock);
if (socketCount++ < CONNECTION_LIMIT) {
Thread serverThread = new Thread(server);
serverThread.start();
} else {
// without starting a thread and notifying only new client
socketCount--;
server.sayGoodbye();
}
}
}
public void sayGoodbye() throws IOException
{
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connectionSocket.getOutputStream())))
{
writer.write("Sorry, a new client connections are exceeding the server limit thus it will not be accepted");
} catch (Exception e)
{
e.printStackTrace();
}
connectionSocket.close();
}
public int getSocket()
{
return socketCount;
}
}
mychat.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class mychat implements Runnable
{
public JTextField tx;
public JTextArea ta;
Server asd = new Server();
public String login="Imed";
BufferedWriter writer;
BufferedReader reader;
public mychat(String l)
{
login=l;
startclient z = new startclient();
JFrame f=new JFrame(z.getName()+"'s Chat");
f.setSize(400,400);
JPanel p1=new JPanel();
p1.setLayout(new BorderLayout());
JPanel p2=new JPanel();
p2.setLayout(new BorderLayout());
tx=new JTextField();
p1.add(tx, BorderLayout.CENTER);
JButton b1=new JButton("Send");
p1.add(b1, BorderLayout.EAST);
ta=new JTextArea();
p2.add(ta, BorderLayout.CENTER);
p2.add(p1, BorderLayout.SOUTH);
f.setContentPane(p2);
try
{
Socket socketClient= new Socket("localhost",5555);
writer= new BufferedWriter(new OutputStreamWriter(socketClient.getOutputStream()));
reader =new BufferedReader(new InputStreamReader(socketClient.getInputStream()));
}
catch(Exception e){e.printStackTrace();}
b1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ev)
{
String s=login+" : "+tx.getText();
tx.setText("");
try
{
writer.write(s);
writer.write("\r\n");
writer.flush();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
);
f.setDefaultCloseOperation (JFrame.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new java.awt.event.WindowAdapter() {
#Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
if (JOptionPane.showConfirmDialog(f,
"Are you sure you want to close this window?", "Close Window?",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION){
asd.getSocket() = asd.getSocket() - 1;
System.exit(0);
}
}
});
f.setVisible(true);
}
public void run()
{
try
{
String serverMsg="";
while((serverMsg = reader.readLine()) != null)
{
System.out.println("from server: " + serverMsg);
ta.append(serverMsg+"\n");
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
startclient.java
import java.util.*;
public class startclient
{
static String name;
public static void main(String [] args)
{
try
{
Scanner sc = new Scanner(System.in);
System.out.print ("Enter your name : ");
name = sc.nextLine();
mychat c=new mychat(name);
Thread t1=new Thread(c);
t1.start();
}
catch(Exception e){e.printStackTrace();}
}
public String getName()
{
return name;
}
}
Every time I try to compile the mychat.java, I get this error message:
mychat.java:13: error: constructor Server in class Server cannot be applied to given types;
Server asd = new Server();
^
required: Socket
found: no arguments
reason: actual and formal argument lists differ in length
mychat.java:90: error: unexpected type
asd.getSocket() = asd.getSocket() - 1;
^
required: variable
found: value
2 errors
I want to limit how many clients can join the server, which kind of works, by adding a new integer called socketCount at Server.java and then increasing the count every time there are new clients joining and if the number of clients is exceeding the server limit, it will reject it.
But it seems that even though I already close the client, the socketCount value is still not decreasing and thus a new client could not enter even though I already giving it places.
Which is why I try to fix it by decreasing the socketCount value at mychat.java every time I close the program, but this error happens.
How can I resolve the error?
You can see the error log here:
mychat.java:13: error: constructor Server in class Server cannot be applied to given types;
Server asd = new Server();
That means you have to put the Socket whenever you create the Server instance.
Your constructor here:
public Server(Socket s){
try{
System.out.println("Client Got Connected " );
connectionSocket=s;
}catch(Exception e){e.printStackTrace();}
}
So, put the Socket to your instance and it should work fine.
Besides that, you should format your codes to be more readable. The class/methods should follow the Coding Convention. It will help you in the future.
Hope this help
Im making a chat program.
i got the client to server connection working but i cant get the server to send to all sockets. Since Im using ObjectOutputStream i cant use PrintWriter which was the way I did it before, Heres my code thanks for the help
Server
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Server {
public Server clients[] = new Server[50];
public static String user;
private static final int PORT = 4000;
private static HashSet<String> names = new HashSet<String>();
private static HashSet<PrintWriter> writers = new HashSet<>();
public static void main(String[] args) throws Exception{
System.out.println("The chatroom is running...");
ServerSocket listener = new ServerSocket(PORT);
try{
while(true){
new Handler(listener.accept()).start();
}
}
catch(Exception e){
System.err.println(e);
}
finally{
listener.close();
}
}
private static class Handler extends Thread{
private String name;
private Socket socket;
//private BufferedReader in;
//private PrintWriter out;
public ObjectOutputStream out;
public ObjectInputStream in;
public void send(Message msg) throws IOException{
out.writeObject(msg);
out.flush();
}
public void Announce(String type, String sender, String content){
Message msg = new Message(type, sender, content, "All");
}
public Handler(Socket socket){
this.socket = socket;
}
public void run(){
try {
out = new ObjectOutputStream(socket.getOutputStream());
out.flush();
in = (new ObjectInputStream(socket.getInputStream()));
out.writeObject(new Message("SUBMITNAME", "blank", "blank", "blank"));
while(true){
Message msg = (Message) in.readObject();
if(msg.sender == null){
return;
}
if(!names.contains(msg.sender)){
names.add(msg.sender);
System.out.println(names.toString());
System.out.println("The object is " + msg);
}
break;
}
while(true){
Message msg = (Message) in.readObject();
System.out.println(msg);
names.add(msg.sender);
System.out.println(names.toString());
break;
}
//out.writeObject(new Message("MESSAGE", "Server", "Welcome To the ChatRoom", "c"));
while(true){
Message msg = (Message) in.readObject();
if(msg.type.equals("MESSAGE")){
out.writeObject(new Message("MESSAGE", msg.sender, msg.content, "all"));
System.out.println(msg.sender + ": " + msg.content);
}
}
}
catch (Exception e) {
System.err.println(e);
}
finally{
try{
socket.close();
System.out.println("Socket has closed");
}
catch(IOException e){
System.err.println("Problem closing socket!");
}
}
}
}
}
Client
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.Socket;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.DefaultCaret;
import static javax.swing.text.DefaultCaret.ALWAYS_UPDATE;
public class Client implements Serializable{
//private BufferedReader in;
//private PrintWriter out;
ObjectOutputStream out;
ObjectInputStream in;
String name;
JFrame frame = new JFrame("Client Box");
JTextField textField = new JTextField(40);
JTextArea messageArea = new JTextArea(8,40);
JScrollPane scroll = new JScrollPane(messageArea);
ArrayList<String> list = new ArrayList();
public Client(){
textField.setEditable(false);
messageArea.setEditable(false);
messageArea.setWrapStyleWord(true);
messageArea.setLineWrap(true);
DefaultCaret caret = (DefaultCaret) messageArea.getCaret();
caret.setUpdatePolicy(ALWAYS_UPDATE);
//frame.setLayout(new BorderLayout());
frame.getContentPane().add(textField, BorderLayout.SOUTH);
frame.getContentPane().add(scroll, BorderLayout.CENTER);
frame.pack();
textField.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
try{
//Message msg = new Message("MESSAGE", name, textField.getText(), "all");
//out.writeObject(msg);
sendAll("MESSAGE", name, textField.getText());
textField.setText("");
}catch(IOException ex){System.err.println(ex.printStackTrace()};
}
});
}
public void sendAll(String type, String sender, String content) throws IOException{
Message msg = (new Message(type, sender, content, "all"));
out.writeObject(msg);
out.flush();
}
private String getName(){
return JOptionPane.showInputDialog(frame, "Your Screen Name?", "Please Enter Screen Name: "
, JOptionPane.PLAIN_MESSAGE);
}
private String getMessage(){
return JOptionPane.showInputDialog(frame, "Your message?", "Please Enter Screen Name: "
, JOptionPane.PLAIN_MESSAGE);
}
private void run() throws IOException, ClassNotFoundException{
//String address = getServerAddress();
Socket socket = new Socket("localhost", 4000);
in = (new ObjectInputStream(socket.getInputStream()));
out = new ObjectOutputStream(socket.getOutputStream());
Message temp = (Message) in.readObject();
if(temp.type.equals("SUBMITNAME")){
textField.setEditable(true);
name = getName();
sendAll(name, "a", " b");
}
while(true){
Message msg = (Message) in.readObject();
messageArea.append(msg.sender + ": " + msg.content + "\n");
}
}
public static void main(String[] args) throws ClassNotFoundException{
Client client = new Client();
client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.frame.setLocationRelativeTo(null);
client.frame.setVisible(true);
try {
try {
client.run();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I didn't realize until now that my disconnect button on my program was failing. If I have 3 clients up, and any of them click disconnect, then only the last client gets disconnected. How do I select which instance I need to close? If out of the 3 users I want to remove the first one..
server:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Server {
private Set<Socket> sockets = new HashSet<Socket>();
private Set<String> names = new HashSet<String>();
private Socket sock;
private static int port;
private Calendar cal = Calendar.getInstance();
private SimpleDateFormat date = new SimpleDateFormat("dd/mm/yyyy hh:mm:ss");
public Server(int input) {
port = input;
}
public static void main(String[] args) {
/*
* user defines port number, server initialized
*/
System.out.println("enter a port");
Scanner input = new Scanner(System.in);
port = input.nextInt();
new Server(port).go();
input.close();
}
public void go() {
try {
/*
* wait for connections, add connections to Set, setup streams per
* connection in new threads
*/
System.out.println("waiting for connetion");
#SuppressWarnings("resource")
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
sock = serverSocket.accept();
sockets.add(sock);
Thread t = new Thread(new ClientHandler(sock));
t.start();
System.out.println("connected: " + sock.getInetAddress());
}
} catch (IOException ex) {
ex.printStackTrace();
System.out.println("server setup failed");
}
}
class ClientHandler implements Runnable {
/*
* client handler sets up streams
*/
private BufferedReader in;
private PrintWriter out;
private String name;
public ClientHandler(Socket sock) {
try {
in = new BufferedReader(new InputStreamReader(
sock.getInputStream()));
out = new PrintWriter(sock.getOutputStream(), true);
} catch (IOException e) {
e.printStackTrace();
System.out.println("stream setup failed");
}
}
#Override
public void run() {
/*
* First check if user exists, if true than close connection and
* warn user about name. Then relay message to all clients, if user
* DC's than remove the socket from the Set
*/
String message;
try {
name = in.readLine();
if (names.contains(name)) {
System.out.println("duplicate name detected, removing..");
out.println("choose new name and reconnect: "
+ sock.getInetAddress());
sock.close();
sockets.remove(sock);
} else {
names.add(name);
System.out.println("Users active: " + names);
shout("user: " + name + " connected!" + " from "
+ sock.getInetAddress());
}
while ((message = in.readLine()) != null) {
/*
* call method which checks if user tries to enter a command
* such as /laugh or /roll, otherwise relay the message to
* all clients
*/
swich(message);
}
} catch (IOException ex) {
System.out.println("user disconnected: " + name + " "
+ sock.getInetAddress());
shout("user disconnected: " + name + " "
+ sock.getInetAddress());
names.remove(name);
remove(sock);
}
}
public synchronized void shout(String message) {
// send message to all clients in Set
for (Socket sock : sockets) {
try {
PrintWriter writer = new PrintWriter(
sock.getOutputStream(), true);
writer.println(date.format(cal.getTime()) + " " + message
+ "\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void swich(String message) throws IOException {
// check if user calls a chat command
// otherwise shout message to all clients
switch (message) {
case "/disconnect":
out.println("disconnected");
remove(sock);
break;
case "/laugh":
String[] laughs = { "HahHA!", "HAHAAH!!!!", "haaaaa!!!",
"hohohoohohahhaa!!!", "huehuehue!" };
shout(name + " " + laughs[(int) (Math.random() * 5)]);
break;
case "/roll":
shout(name + " rolls "
+ Integer.toString((int) ((Math.random() * 6) + 1)));
break;
case "kirby!":
shout("(>'-')> <('-'<) ^(' - ')^ <('-'<) (>'-')>");
break;
default:
shout(message);
System.out.println("client says : "
+ date.format(cal.getTime()) + message);
}
}
}
public void remove(Socket soc) {
try {
soc.close();
sockets.remove(soc);
} catch (IOException e) {
e.printStackTrace();
}
}
}
client:
import java.awt.BorderLayout;
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 java.util.Scanner;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Client {
private JTextArea tArea;
private JTextField tField;
private JTextField portText;
private JTextField hostText;
private BufferedReader in;
private Socket sock;
private static PrintWriter out;
private static String name;
private String host;
private String port;
public static void main(String[] args) {
System.out.println("Enter username");
Scanner input = new Scanner(System.in);
name = input.nextLine();
input.close();
new Client().go();
}
public void go() {
/*
* build gui
*/
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("hakobChat");
JPanel topPanel = new JPanel();
JLabel portLabel = new JLabel("port");
JLabel hostLabel = new JLabel("host");
portText = new JTextField(6);
hostText = new JTextField(12);
JButton connect = new JButton("connect");
connect.addActionListener(new connectListener());
JButton disconnect = new JButton("disconnect");
disconnect.addActionListener(new disconnectListener());
tField = new JTextField(30);
tField.addActionListener(new sendListener());
tArea = new JTextArea(30, 50);
tArea.setEditable(false);
tArea.setLineWrap(true);
JScrollPane tScroll = new JScrollPane(tArea,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JButton button = new JButton("send");
button.addActionListener(new sendListener());
topPanel.add(hostLabel);
topPanel.add(hostText);
topPanel.add(portLabel);
topPanel.add(portText);
topPanel.add(connect);
topPanel.add(disconnect);
frame.setSize(300, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(topPanel, BorderLayout.NORTH);
frame.getContentPane().add(tScroll, BorderLayout.CENTER);
frame.getContentPane().add(tField, BorderLayout.SOUTH);
frame.getContentPane().add(button, BorderLayout.EAST);
frame.pack();
}
});
}
public void setupNetwork(String host, int port) {
/*
* setup in and out stream send user name to server to check if
* duplicate start thread for incoming messages
*/
try {
sock = new Socket(host, port);
in = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
out = new PrintWriter(sock.getOutputStream(), true);
out.println(name);
showMessage("Connected!");
showMessage("enter /laugh or /roll or kirby! for some fun!");
Thread t = new Thread(new IncomingReader());
t.start();
} catch (IOException ex) {
ex.printStackTrace();
showMessage("please enter valid network");
}
}
class IncomingReader implements Runnable {
// receive messages from server
public void run() {
try {
String message = null;
while ((message = in.readLine()) != null) {
showMessage(message + "\n");
}
} catch (Exception e) {
e.printStackTrace();
showMessage("choose new name and reconnect please");
}
}
}
public synchronized void sendMessage(String message) {
try {
switch (message) {
case "/laugh":
out.println("/laugh");
break;
case "/roll":
out.println("/roll");
break;
case "kirby!":
out.println("kirby!");
break;
default:
out.println("(" + name + ")" + ": " + message);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("fail send message");
}
}
public void showMessage(final String message) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
tArea.append(message + "\n");
tArea.setCaretPosition(tArea.getDocument().getLength());
// SetCaretPosition forces autos scroll
}
});
}
class sendListener implements ActionListener {
// listens for user to trying to send a message
public void actionPerformed(ActionEvent ev) {
sendMessage(tField.getText());
tField.setText("");
}
}
class disconnectListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
try {
out.println("/disconnect");
} catch (NullPointerException e) {
showMessage("not connected");
}
}
}
class connectListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
host = hostText.getText();
port = portText.getText();
if (!host.equals("") && !port.equals("") && port.matches("[1-9]+")) {
// make sure user enters valid inputs
// before setting up network
setupNetwork(host, Integer.parseInt(port));
} else {
showMessage("enter valid network credentials");
}
}
}
}
Also, how do I avoid this "#SuppressWarnings("resource")". If I don't have this eclipse provided warning than the serverSocket is underlined yellow.
You need to save a the Socket used for the client inside of the ClientHandler.
You can do this by simply adding a
private Socket sock;
inside of ClientHandler, and adding:
this.sock = sock;
inside of its constructor.
Currently you're using the Socket saved in the server, which will always be the socket of the last client that connected, rather than the Socket belonging to the current client.
This is just a scoping problem. The Socket sock member shouldn't be part of the Server class. It should be part of the ClientHandler class. One per client.