LinuxQuestions.org
Support LQ: Use code LQ3 and save $3 on Domain Registration
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices



Reply
 
Search this Thread
Old 08-24-2006, 11:05 AM   #1
Mega Man X
Guru
 
Registered: Apr 2003
Location: ~
Distribution: Ubuntu, FreeBSD, Solaris, DSL
Posts: 5,339

Rep: Reputation: 63
Java Sockets: Help with a simple chat client/server


Hi all!!

I'm trying to write a simple server and a client chat program with Java, but I'm facing some problems here. Basically, the server supports multi-clients and I can send messages and receive messages from the server without a problem back to the client.

Problem: Suppose I have 2 clients connected to the server. Client1 sends a message "Hello" and the server send that message back to Client1. The problem is, I want Client2 to also receive the message Client1 sent. The way it is working now, the server can receive and communicate with any client, but I want the clients to be able to communicate with themselves through the server and displaying each other messages on the client itself. Is that possible?

With the way it is working now, I could simply use the server as an Applet (with a few modifications) and all clients would connect to the server and be able to talk without a problem. But that is not quite what I want ^_^.

This seems ratter difficult, since for each client connected to the server, a new thread is created. I'm not sure how to fix this, if at all possible. But here is the code for both client and server. It should be easier for you to visualize what I'm trying to do:

// Server
Code:
import java.io.*;
import java.net.*;
import java.util.*;
import java.awt.*;
import javax.swing.*;

public class MultiThreadServer extends JFrame {
    
    private JTextArea jta = new JTextArea();

    /** Creates a new instance of SimpleServer */
    public MultiThreadServer() {
        // place text area on the frame
        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(new JScrollPane(jta), BorderLayout.CENTER);
        
        setTitle("Simple Server");
        setSize(500, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);

        jta.setEditable(false);
        
        try {
            ServerSocket serverSocket = new ServerSocket(4242);
            System.out.println("Server is upp and running");
            jta.append("Server started at " + new Date() + "\n");
            
            String messageReceived = null;
            
            while (true) {
                
            Socket socket = serverSocket.accept(); // accept connections
            
            InetAddress inetAddress = socket.getInetAddress(); // used to get host information
            
            /* Get host IP and hostname and display on the window */
            jta.append("Client connected to the server!\n" + 
                    "Client's host name is: " + inetAddress.getHostName() + "\n" +
                    "Client's IP Address is: " + inetAddress.getHostAddress() + "\n");
            
            // Create a new thread for connection
            HandleAClient thread = new HandleAClient(socket);
            
            thread.start();

            }
        }
        catch (IOException ex) {
            System.err.println(ex);
        }
        
    }
    
    public static void main(String[] args) {
        new MultiThreadServer();
    }

    // inned class to handle a new connection
    class HandleAClient extends Thread {
    
        private Socket socket; // a connected socket
    
        /** Creates a new thread */
        public HandleAClient(Socket socket) {
            this.socket = socket;
        }
    
        public void run() {
            try {
            
                DataInputStream inputFromClient = new DataInputStream(socket.getInputStream());
                DataOutputStream outputToClient = new DataOutputStream(socket.getOutputStream());
    
                while (true) {
                
                    String messageReceived = inputFromClient.readUTF();
                                                
                    // this is more like a joke. Ignore this ^_^
                    if (messageReceived.equals("+kill_server")) {
                        System.exit(0);
                    }
                                
                    outputToClient.writeUTF(messageReceived);
                
                    jta.append("User said: " + messageReceived);
   
                }
        
            } catch (IOException ex) {
                System.err.println(ex);
            }
       }
        
    } // close handle client
    
} // close MultiThreadServer
// Client
Code:
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.awt.*;
import javax.swing.*;

public class SimpleClient extends JFrame implements ActionListener {
    
    private JTextField jtfMessageToSend = new JTextField();
    
    private JTextArea jtaMessageReceived = new JTextArea();
    
    private JButton btnSend = new JButton("Send");
    
    private DataOutputStream toServer;
    
    private DataInputStream fromServer;
    
    /** Creates a new instance of SimpleClient */
    public SimpleClient() {
        
        JPanel p = new JPanel();
        p.setLayout(new BorderLayout());
        p.add(new JLabel("Message to send: "), BorderLayout.WEST);
        btnSend.addActionListener(this);
        btnSend.setMnemonic('s');
        p.add(btnSend, BorderLayout.EAST);
        p.add(jtfMessageToSend, BorderLayout.CENTER);
        jtfMessageToSend.setHorizontalAlignment(JTextField.LEFT);
        jtaMessageReceived.setEditable(false);
        
        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(p, BorderLayout.SOUTH);
        getContentPane().add(new JScrollPane(jtaMessageReceived), BorderLayout.CENTER);
        
        jtfMessageToSend.addActionListener(this);
        
        setTitle("SimpleClient");
        setSize(500, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        
        try {
            Socket socket = new Socket("localhost", 4242);
            
            fromServer = new DataInputStream(socket.getInputStream());
            
            toServer = new DataOutputStream(socket.getOutputStream());
            
        }
        catch (IOException ex) {
            jtaMessageReceived.append(ex.toString());
        }
        
    }

    public void actionPerformed(ActionEvent e) {
        String actionCommand = e.getActionCommand();
        if (e.getSource() instanceof JTextField || e.getSource() == btnSend) {
            try {
                toServer.writeUTF(jtfMessageToSend.getText());
                toServer.flush();
                jtfMessageToSend.setText("");
                
                String messageToDisplay = fromServer.readUTF();
                jtaMessageReceived.append(messageToDisplay + "\n");
                
            }
            catch (IOException ex) {
                System.err.println(ex);
            }
        }
    }
    
    public static void main(String[] args) {
        new SimpleClient();
    }
    
}
Thanks a lot in advance for any help!
 
Old 08-24-2006, 12:03 PM   #2
rednuht
Member
 
Registered: Aug 2005
Posts: 239
Blog Entries: 1

Rep: Reputation: 30
instead of just creating the thread for a new client
Code:
// Create a new thread for connection
HandleAClient thread = new HandleAClient(socket);
add the client to vector list
Code:
Vclients  = new Vector();
...
// Create a new thread for connection
HandleAClient thread = new HandleAClient(socket);
Vclients.addElement(HandleAClient);
then loop through the vector list and send the message to each client.
Code:
for (int i=0;i<sD.Vclients.size();i++) {
    ((HandleAClient)Vclients.elementAt(i)).send("some message");
}
my client thread class has a send method that should be easy to impliment
 
Old 08-24-2006, 12:43 PM   #3
Mega Man X
Guru
 
Registered: Apr 2003
Location: ~
Distribution: Ubuntu, FreeBSD, Solaris, DSL
Posts: 5,339

Original Poster
Rep: Reputation: 63
Very good idea rednuht!. Thanks. I've just tried it out and it works. I'm having some problems with the flush() method, but I will fix that once I know what that does exactly ^_^.

In the meanwhile, I've been trying to integrate the server and the client. Basically, one application would be the "Server and Client" and the other only a client. This would not accept multiples clients, but it would do just fine for what I need right now. However, when I send a message to "Simple Client" from "Server and Client" or a message from the "Simple Client" to the "Server and Client", they lock each other up. I think it has something to do with the "flush()" method. Problem is, Daniel Liang's book does not explain very well what flush() does (I hate this book actually).

Anyway, can anyone see why this is not working:

Code:
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.awt.*;
import javax.swing.*;

public class ServerAndClient extends JFrame implements ActionListener {
    
    private JTextField jtfMessageToSend = new JTextField();
    
    private JTextArea jtaMessageReceived = new JTextArea();
    
    private JButton btnSend = new JButton("Send");
    
    private DataInputStream fromClient;
    
    private DataOutputStream toClient;
    
    
    /** creates a new instance of ServerAndClient */
    public ServerAndClient() {
        
        JPanel p = new JPanel();
        p.setLayout(new BorderLayout());
        p.add(new JLabel("Message to send: "), BorderLayout.WEST);
        btnSend.addActionListener(this);
        btnSend.setMnemonic('s');
        p.add(btnSend, BorderLayout.EAST);
        p.add(jtfMessageToSend, BorderLayout.CENTER);
        jtfMessageToSend.setHorizontalAlignment(JTextField.LEFT);
        jtaMessageReceived.setEditable(false);
        
        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(p, BorderLayout.SOUTH);
        getContentPane().add(new JScrollPane(jtaMessageReceived), BorderLayout.CENTER);
        
        jtfMessageToSend.addActionListener(this);
        
        setTitle("Simple Client and Server");
        setSize(500, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        
        try {
            ServerSocket serverSocket = new ServerSocket(4242);
            System.out.println("Server is upp and running");
            jtaMessageReceived.append("Server started at " + new Date() + "\n");
            
            Socket socket = serverSocket.accept(); // accept connections
            
            InetAddress inetAddress = socket.getInetAddress(); // used to get host information
            
            /* Get host IP and hostname and display on the window */
            jtaMessageReceived.append("Client connected to the server!\n" +
                    "Client's host name is: " + inetAddress.getHostName() + "\n" +
                    "Client's IP Address is: " + inetAddress.getHostAddress() + "\n");
            
            fromClient = new DataInputStream(socket.getInputStream());
            toClient = new DataOutputStream(socket.getOutputStream());
            
            String messageReceived = null;
            
            
            while (true) {
                messageReceived = fromClient.readUTF();
                
                if (messageReceived.equals("+kill_server")) {
                    System.exit(0);
                }
                
                jtaMessageReceived.append(inetAddress.getHostName() + " said: " + messageReceived + "\n");
                
                // toClient.writeUTF(messageReceived);
                
            }
        } catch (IOException ex) {
            System.err.println(ex);
        }
        
    }
    
    public void actionPerformed(ActionEvent e) {
        String actionCommand = e.getActionCommand();
        
        if (e.getSource() instanceof JTextField || e.getSource() == btnSend) {
            try {
                toClient.writeUTF(jtfMessageToSend.getText());
                //toClient.flush();
                jtfMessageToSend.setText("");
                
                String messageToDisplay = fromClient.readUTF();
                jtaMessageReceived.append(messageToDisplay + "\n");
                
            } catch (IOException ex) {
                System.err.println(ex);
            }
        }
        
        
    }
    
    public static void main(String[] args) {
        new ServerAndClient();
    }
    
}
Code:
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.awt.*;
import javax.swing.*;

public class SimpleClient extends JFrame implements ActionListener {
    
    private JTextField jtfMessageToSend = new JTextField();
    
    private JTextArea jtaMessageReceived = new JTextArea();
    
    private JButton btnSend = new JButton("Send");
    
    private DataOutputStream toServer;
    
    private DataInputStream fromServer;
    
    /** Creates a new instance of SimpleClient */
    public SimpleClient() {
        
        JPanel p = new JPanel();
        p.setLayout(new BorderLayout());
        p.add(new JLabel("Message to send: "), BorderLayout.WEST);
        btnSend.addActionListener(this);
        btnSend.setMnemonic('s');
        p.add(btnSend, BorderLayout.EAST);
        p.add(jtfMessageToSend, BorderLayout.CENTER);
        jtfMessageToSend.setHorizontalAlignment(JTextField.LEFT);
        jtaMessageReceived.setEditable(false);
        
        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(p, BorderLayout.SOUTH);
        getContentPane().add(new JScrollPane(jtaMessageReceived), BorderLayout.CENTER);
        
        jtfMessageToSend.addActionListener(this);
        
        setTitle("SimpleClient");
        setSize(500, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        
        try {
            Socket socket = new Socket("localhost", 4242);
            
            fromServer = new DataInputStream(socket.getInputStream());
            
            toServer = new DataOutputStream(socket.getOutputStream());
            
        }
        catch (IOException ex) {
            jtaMessageReceived.append(ex.toString());
        }
        
    }

    public void actionPerformed(ActionEvent e) {
        String actionCommand = e.getActionCommand();
        if (e.getSource() instanceof JTextField || e.getSource() == btnSend) {
            try {
                toServer.writeUTF(jtfMessageToSend.getText());
                toServer.flush();
                jtfMessageToSend.setText("");
                
                String messageToDisplay = fromServer.readUTF();
                jtaMessageReceived.append(messageToDisplay + "\n");
                
            }
            catch (IOException ex) {
                System.err.println(ex);
            }
        }
    }
    
    public static void main(String[] args) {
        new SimpleClient();
    }
    
}
The "Simple Client" is basically the same, the "Client and Server" is a mix of both. I can't understand why this is not working.
 
Old 08-24-2006, 04:27 PM   #4
rednuht
Member
 
Registered: Aug 2005
Posts: 239
Blog Entries: 1

Rep: Reputation: 30
When you send data to a dataInputStream with for instance the writeUTF method the data goes into a queue and is only sent when the queue is full, the operating system automatically flushes it or you explicitly flush it with a call to the flush method.
Problem being, unless you use another thread to do the flushing this blocks your current thread, also you have the complexities of the network traffic, firewalls etc.
I suggest installing ethereal (now called wireshark) and view what is happening when, I remember writing a very simular java chat system and it quickly got complicated, lots and lots of debug trace information had to be produced by the server app to track even the simplest issue.
 
Old 08-24-2006, 05:41 PM   #5
Mega Man X
Guru
 
Registered: Apr 2003
Location: ~
Distribution: Ubuntu, FreeBSD, Solaris, DSL
Posts: 5,339

Original Poster
Rep: Reputation: 63
Thanks again for your reply rednuht! I really appreciated your input ^^. I still could not manage to fix the Client And Server application. I've been hunting the net for examples, but as you said, things can get really complicated. I think I will stick with the working program and see how it goes.

There is a very cool Java Messenger around which works pretty much like Gaim does. I wonder how much work that should take when working with plenty of protocols at the same time... I can barely send a hello from a client to a server, hihi
 
Old 07-10-2009, 08:26 AM   #6
streetfi8er
LQ Newbie
 
Registered: Feb 2009
Posts: 2

Rep: Reputation: 0
Quote:
Originally Posted by rednuht View Post
instead of just creating the thread for a new client
Code:
// Create a new thread for connection
HandleAClient thread = new HandleAClient(socket);
add the client to vector list
Code:
Vclients  = new Vector();
...
// Create a new thread for connection
HandleAClient thread = new HandleAClient(socket);
Vclients.addElement(HandleAClient);
then loop through the vector list and send the message to each client.
Code:
for (int i=0;i<sD.Vclients.size();i++) {
    ((HandleAClient)Vclients.elementAt(i)).send("some message");
}
my client thread class has a send method that should be easy to impliment

what does the statement "Vclients.addElement(HandleClient)" store in the vector?
how do i proceed if i want to add each client by their names??
 
Old 07-15-2009, 06:16 PM   #7
arashi256
Member
 
Registered: Jan 2008
Location: Brighton, UK
Distribution: Ubuntu 12.04 / CentOS 6.5
Posts: 387

Rep: Reputation: 61
I've got some Java code for a Client/Server chat system - it's unfinished as of this moment, but you can join the server and chat to all connected clients and also kick users off and various other stuff (can't remember...lol). The only problem at the moment is that the server side software seems to soak up an awful lot of CPU resources, so that needs tweaking for performance...probably something to do with the Threading design. Not looked at it for a while now. Anyway, you can have it if you want. I was going to add the capability to private message another user in a separate window but never got around to it.

Mail me via my MSN in my profile if you are interested.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
chat program in client-server mode iman2380 Programming 4 06-01-2006 07:50 AM
client/server question (with sockets) bicycle Programming 1 11-24-2005 02:26 PM
Sockets Programing Client/Server ashucool83 Programming 9 09-30-2005 03:43 PM
Chat Server and web/java client Mercury3 Linux - Software 5 05-19-2004 11:39 AM
Server/Client-commucation via TCP-Sockets cYbORg Programming 5 05-18-2003 07:01 PM


All times are GMT -5. The time now is 10:17 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration