I'm writing a WebChat application using the socket functions in java.

I'm able to listen for incoming sockets on the server side and connect from the client side just fine, but I'm having a problem communicating from the client to the server to ALL the clients.

Right now, I have it set up so my ServerSocket is running in its own thread, constantly listening for connections on a specified port. If it receives a connection, it opens up another thread dedicated to the client socket.

So now, the client socket can communicate back and forth with just the client. What would be a good way to make it able to communicate with ALL the other clients simultaneously? Is taking this kind of socket approach the right way to do something like this? What would be better?

Recommended Answers

All 10 Replies

Not sure if this is the best way, but I was able to get it working by creating a list of each of my accepted SocketThreats ( the ones accepted by the ServerSocket ):

List<SocketThread> sockets = ArrayList<SocketThread>();

and just using a for loop to broadcast to everyone on the list instead of just the originating socket.

Was thinking of doing that, but was wondering if there was an easier way.

This comes up quite often, and keeping a list of open socket threads and broadcasting in a loop is the right way to go.
You'll need to remove socket threads from the list when the sockets close (or fail), and that's quite likely to happen when you try to send to them during the broadcast. That will give you a concurrent modification exception on the list of socket threads, so do the broadcast on a temporary copy of the list.

I'm having a problem adding the sockets correctly to the list because its passing the thread to the list by value...

Its actually creating 2 threads.. The original one thats created and then the copied one thats passed into the list by value...... There has to be a better way.. Stupid java! why dont u let me choose to pass by reference! :)

>I'm having a problem adding the sockets correctly to the list because
>its passing the thread to the list by value...

In Java, object references are passed by value or in simple terms, Java has pass by reference when it comes to objects. Posting a bit of code to highlight your problem would be a good idea.

Java has pass by reference when it comes to objects

really? hmmm..... Now that I changed my code back, it looks like you were right.. My code was getting a little complex and I thought this was the problem, but it wasnt....

Here is where I thought 2 threads were created and one was passed by value:

public void run() {
	boolean listening = true;
	ServerSocket serverSocket;
	List<SocketThread> sockets = Collections.synchronizedList(new ArrayList<SocketThread>());

	try {
		serverSocket = new ServerSocket(port);
	
		while (listening) {
			sockets.add(new SocketThread(serverSocket.accept()));    //right here
		}
		
		serverSocket.close();
	} catch (IOException e) {
		System.err.println("SERVER: Could not listen on port: " + port);
		e.printStackTrace();
		System.exit(-1);
	}
}

Isn't everything essentially an Object though? How does Java know what to pass by reference and what to pass by value? I wish it would give you an option like C/C++... So many areas were it makes more sense...

In Java some things are not Objects - ints, booleans etc (all the types whose name begins with a lower case letter). These are simple primitive values. Everything else is an object... or a reference to an object. Java keeps the syntax simple by hiding the difference between object and reference-to-object.
SomeClass foo; creates a reference-to-object, initially with the value null.
new SomeClass(...) creates an object.
SomeClass foo = new SomeClass(...); creates an object, and then sets foo to be a reference to that object.
myCollection.add(foo); passes foo as a parameter by placing a copy of it on the stack - but since foo is a reference-to-object, it's the reference that's passed by value, not the object. This effectively passes the object by reference.
So. primitives are passed by value, and objects are passed by reference because all parameters are object references, not objects.

Ugh. this is still kind of confusing. Let me make sure I get this right:

serverSocket.accept() //returns not a socket, but a reference to a socket because a "Socket" would be considered an object.

new SocketThread(socket), in which the SocketThread looks like this:

public class SocketThread  extends Thread {
     Socket socket = null;

     public SocketTherad(Socket socket) {
          contains this.socket = socket;
          ....
     }
     .....
}

whould assign Socket socket = null, the reference of the socket that was accepted.


and then, sockets.add(SocketThread) would add to the sockets list, not the new SocketThread() itself, but the reference to the active SocketThread created?

All of this is done by reference?

sockets.add(new SocketThread(serverSocket.accept()));
Passes a reference to a Socket into a reference of a SocketThread into a list of references of SocketThreads.

Right? or Wrong? lol

You said:
>SomeClass foo; creates a reference-to-object, initially with the value null.
>new SomeClass(...) creates an object.

In that case, would this be any different than the 1 liner above:

Socket socket = serverSocket.accept();
SocketThread socketThread = new SocketThread(socket);
sockets.add(socketThread);

that way references-to-objects are passed all the way through and not the actual objects or are they the same?

Despite the misleading way that Java semantics work, socket and socketThread are not objects, they are references-to-objects. Their values (ie the references) are passed by value (a copy of the value is placed on the stack when the method is called). That way all those methods get references to the real objects, which are sitting somewhere in the JVM's memory and only accessible via a reference-to-object.
However, for most practical purposes its perfectly OK to think of the objects as being passed by reference, and to ignore all these pedantic details.

Thanks...

remember the code snipit from up top:

List<SocketThread> sockets = Collections.synchronizedList(new ArrayList<SocketThread>());

while (listening) {
	sockets.add(new SocketThread(serverSocket.accept()));    //ST's constructor calls this.start();
}

well, i add to do this:

List<SocketThread> sockets = Collections.synchronizedList(new ArrayList<SocketThread>());

while (listening) {
	sockets.add(new SocketThread(serverSocket.accept()));  //ST's constructor no longer calls this.start()
	sockets.get(sockets.size()-1).start(); //instead, call it here
}

I thought the problem was something we were talking about, but it was because I was using a synchronized list (which blocks so only 1 thread has access to the list at a time)...

My SocketThread was using this sockets list BEFORE it added the new socket to it.... duh :)

Thank you though. I would have been stuck on this problem for a long time, thinking that it was passing a copy of the object itself instead of its reference by value. This cleared up a big question I had while programming.


Side note: any better way to do this than using a synchronized list to hold each socket? I used a synchronized list because I needed something which can dynamically be sized (no telling how many users will be joining the server), be accessed by multiple threads safely (which is why its synchronized) and allow easy adding, removing and searching functions. I believe this is the best way to do it, correct?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.