Jump to content

Socket Programming

- - - - -

  • Please log in to reply
8 replies to this topic

#1
fread

fread

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 787 posts
I have been playing around with some socket programming code i found online. In essence its a client server application(chat server) that accepts a string from a client and broadcast the string to all clients. One problem: after receiving the string from the client the server attempts to iterate all of the saved DataOutputStreams and broadcast a message. For some reason the message is unable to reach the client program(s). I tested with my own server app(more or less a single TCP connection) and the client can communicate successfully with the server. I stripped out most of my code.

Here is most of the original code:
package Chat;

import java.io.*;
import java.net.*;
import java.util.*;

public class Server
{
    // The ServerSocket we'll use for accepting new connections
    private ServerSocket serverSocket;
    private int num_active_chats;
    
    // A mapping from sockets to DataOutputStreams. This will
    // help us avoid having to create a DataOutputStream each time
    // we want to write to a stream.
    private Hashtable outputStreams = new Hashtable();

    // Constructor and while-accept loop all in one.
    public Server( int port ) throws IOException 
    {
        // All we have to do is listen
        num_active_chats = 0;
        InetAddress IPAddress = InetAddress.getLocalHost();

        System.out.println("server ip: " + IPAddress);
        listen( port );
    }
    
    private void listen( int port ) throws IOException 
    {
        // Create the ServerSocket
        serverSocket = new ServerSocket( port );
        // Tell the world we're ready to go
        System.out.println( "Listening on "+serverSocket );
        
        // Keep accepting connections forever
        while (true) 
        {
            // Grab the next incoming connection
            Socket socket = serverSocket.accept();
            // Tell the world we've got it
            System.out.println( "Connection from "+socket );
            
            // Create a DataOutputStream for writing data to the
            // other side
            DataOutputStream data_out = new DataOutputStream( socket.getOutputStream() );
            
            // Save this stream so we don't need to make it again
            outputStreams.put( socket, data_out );
            
            // Create a new thread for this connection, and then forget
            // about it
            new ServerThread( this, socket );
            
            //update the number of clients online
            num_active_chats++;
        }
    }
    
    // Get an enumeration of all the OutputStreams, one for each client
    // connected to us
    Enumeration getOutputStreams() 
    {
        return outputStreams.elements();
    }
    //Filter then broadcast Message
    public void Broadcast(String message)
    {
       /* if (filterMessage(message) == true)
        {
            System.out.println("Control message filtered " + message);
        }
        else*/ sendToAll(message);
        
    }
    
    //remove control messages and logs
    private boolean filterMessage(String message)
    {
        
        return false;
    }
    
    // Send a message to all clients (utility routine)
    void sendToAll( String message ) 
    {
        // We synchronize on this because another thread might be
        // calling removeConnection() and this would screw us up
        // as we tried to walk through the list
        System.out.println("broadcasting: " + message);
        synchronized( outputStreams ) 
        {
            // For each client ...
            for (Enumeration e = getOutputStreams(); e.hasMoreElements(); ) 
            {
                // ... get the output stream ...
                DataOutputStream sentence_out = (DataOutputStream)e.nextElement();
                // ... and send the message

                try {
                   
                    sentence_out.writeBytes( message ); //this line does not reach the client app(s)
                    
                    } catch( Exception ie ) { System.out.println( ie ); }
            }
        }
    }
    
    // Remove a socket, and it'socket corresponding output stream, from our
    // list. This is usually called by a connection thread that has
    // discovered that the connectin to the client is dead.
    void removeConnection( Socket somesocket ) 
    {
        // Synchronize so we don't mess up sendToAll() while it walks
        // down the list of all output streamsa
        synchronized( outputStreams ) 
        {
            //update the number of clients online
            num_active_chats--;
            
            // Tell the world
            System.out.println( "Removing connection to "+somesocket );
            // Remove it from our hashtable/list
            outputStreams.remove( somesocket );
            // Make sure it'socket closed
            try {
                somesocket.close();
                } catch( IOException ie ) 
                {
                    System.out.println( "Error closing "+somesocket );
                    ie.printStackTrace();
                }
        }
    }

    // Main routine
    // Usage: java Server <port>
    static public void main( String args[] ) throws Exception 
    {
        
        int port = 5555;
        // Create a Server object, which will automatically begin
        // accepting connections.
        new Server( port );
    }

    private void programData(String message) 
    {
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

Thread class:
package Chat;

import java.io.*;
import java.net.*;

public class ServerThread extends Thread
{
    // The Server that spawned us
    private Server server;

    // The Socket connected to our client
    private Socket socket;
   
    // Constructor.
    public ServerThread( Server server, Socket socket ) 
    {
        // Save the parameters
        System.out.println("Creating client thread");
        this.server = server;
        this.socket = socket;
        // Start up the thread
        start();
    }
    // This runs in a separate thread when start() is called in the
    // constructor.

    @Override
    public void run() 
    {
        try {
            // Create a DataInputStream for communication; the client
            // is using a DataOutputStream to write to us
            //System.out.println("run method in serverthread");
            BufferedReader sentence_in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //DataInputStream din = new DataInputStream( socket.getInputStream() );
            // Over and over, forever ...
            while (true) 
            {
                // ... read the next message ...
                String message = sentence_in.readLine();
                // ... tell the world ...
                //System.out.println( "Sending "+message );
                // ... and have the server send it to all clients
                server.Broadcast( message );
            }
            } catch( EOFException ie ) 
            {
                //will not be reading from files
            } catch( IOException ie ) 
            {
                System.out.println("input/output error");
                ie.printStackTrace();
            } finally 
                {
                    // The connection is closed for one reason or another,
                    // so have the server dealing with it
                    server.removeConnection( socket );
                }
    }
}


Perfection of means and confusion of ends seem to characterize our age. Albert Einstein :confused:

#2
wim DC

wim DC

    Writes binary right handed and hex left handed

  • Members
  • PipPipPipPipPipPipPipPipPip
  • 2,084 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Java
It's most likely cause the client side doesn't flush() or doesn't send lines meaning you must also send \n, \r\n or something like that to finish the line.

#3
fread

fread

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 787 posts
goodcall. I originally appended the '\n' on the client end side, did not realise it would be necessary on the server side as well. Quick question, if i want to record and store information from each client, like user names, system properties, chat logs etc., all of which i would like to implement within the server-side code, what would you recommend.
Perfection of means and confusion of ends seem to characterize our age. Albert Einstein :confused:

#4
wim DC

wim DC

    Writes binary right handed and hex left handed

  • Members
  • PipPipPipPipPipPipPipPipPip
  • 2,084 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Java
Create a client class at the server side, which is not actually a client as in it will talk to the server, it's just an object that contains info of the client. You can also put the socket and streams in it.

#5
fread

fread

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 787 posts
Yes i was thinking about doing that but my concern is more about the actual storage of the data. Whether to use some kind of persistent storage or text files or probably use JDBC or something else. I know there are pros and cons of using any method so I am just looking for opinions.
Perfection of means and confusion of ends seem to characterize our age. Albert Einstein :confused:

#6
wim DC

wim DC

    Writes binary right handed and hex left handed

  • Members
  • PipPipPipPipPipPipPipPipPip
  • 2,084 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Java
If you plan to use this application only for yourself a file will do. Put the Client objects in an ArrayList and write it to a file. Your Client class must be serializable for this.

As the amount of clients grows this gets worse and worse because you always read the whole arraylist from the file at once.
Say your server knows 14000 clients, it will have to load them all in the memory to retrieve the arraylist. This may take a lot of memory and possibly cause outofmemory errors.
In that case you don't want to have all the clients in the memory, but just the ones you really need and a database seems like the best option to store them in then.

An alternative is to store each client in his own file so that takes away the problem of having to load so many. But in a database you can easily query the ones you need like:
Select * from clients where ip IN('127.0.0.1', '127.0.0.2')

And this goes at a VERY decent speed. If you would have to do that manually that will propably mean you will have to load each client one by one - file by file- and then check the info
and that will be much much slower than a database.

The only downside I can think of using a database is writing the code to get your objects to and from the database.
Certainly when Client will get relations this quickly becomes a huge pain in the :w00t:. At that point you should look into JPA.

#7
fread

fread

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 787 posts
I intend to use it as a LAN chat where i work. B/c messenger programs like windows live are blocked with a heap of other stuff (but i have permission to use over the LAN as long as i don't need to physically access their servers). Should not be more than 100 persons at once. May also use in the lab at school for demonstration purposes.
Perfection of means and confusion of ends seem to characterize our age. Albert Einstein :confused:

#8
wim DC

wim DC

    Writes binary right handed and hex left handed

  • Members
  • PipPipPipPipPipPipPipPipPip
  • 2,084 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Java
100 is peanuts, you can just read and write that to a file :)

Why do you actually plan to store? I mean if the server stops and restarts it can have all that client data... but I see little use with it.

#9
fread

fread

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 787 posts
Well I want to server to be very robust and info gathering, managing and monitoring. It is more or less to be used as a demonstration program, while having some fun. I also want to extend the app for mobile clients and possibly some Bluetooth (not sure if Bluetooth is feasible let alone worth while).
Perfection of means and confusion of ends seem to characterize our age. Albert Einstein :confused:




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users