a loop in the server which reads all the client sockets - java

Suppose that i have a class ServerReader which is a Thread that runs all the time. the ServerReader have a loop that reads all the messages from all client in a way like this:
while(true) {
for(Socket socket: sockets_arraylist) {
ObjectInputStream object_stream = new ObjectInputStream(socket.getInputStream());
String str = (String) object_stream.readObject();
System.out.println("message from client: " + str);
object_stream.close();
}
}
As i understand, when the loop encounter readObject() method, the Thread is going to sleep until the client actually sending an object.
So imagine this scenerio:
the ArrayList "sockets_arraylist" contains 2 sockets. The second socket on the list, which belongs to client number 2 waiting to recieve a message. Client number 2 sending this message and wait for the server to read it. But there is a problem: the loop above stuck at readObject() method that waits for the message from client 1. so until client 1 will not send his message to the server, client`s 2 message will not be read.
Do i need to make on the server a separete thread for each client? or there is another solution?

There are two solutions:
1) Use a separate thread for each client.
2) Use asynchronous IO using java.nio - in this case you'd probably want SocketChannel.
Using a separate thread for each client is likely to be conceptually simpler, although it does mean you need to consider race conditions more carefully. Using NIO may be more scalable (different benchmarks show different results, and it may well depend on your OS as well, in terms of how costly threads and scheduling are.)

Related

Java - Recognise sent-to-one and sent-to-all messages from server, on the client-side

I am working on a server/client application that allows multiple clients to be connected to the server at any given time.
For each client, the server sets up a ClientHandler object that has an input and output stream to the client connected at this socket. Through this connection, the client is free to send a number of messages to the server at any point throughout the running of the program, and the server will respond according to the message.
What I need to implement is a mechanism that sends, at certain times, messages to all currently-connected clients. I have done this by storing all the output streams to clients in an ArrayList<PrintWriter> that will allow the same message to be sent to all clients.
What I am struggling with is this:
When a message is received that is individual to the client, the client GUI is updated accordingly (only a select number of messages can be sent, so there only a select number of possible responses-from-server, dealt with by client-side if statements). However, when a message is received by the client that was sent to all clients, I would like the client to update the GUI quite differently.
Considering that both forms of input come from the same input stream, I can see this being difficult, and I anticipate that I will have to declare any methods that cause output using the PrintWriter will have to be made synchronized. However, is there a way to process the different inputs while using the same PrintWriter at all? Would this have to be done using further if statements or could it be done using a separate Thread on the client side that handles messages sent to all clients?
Thanks for any advice, if you think you can help then feel free to ask for parts of my existing code!
Mark
You are first of all lacking a protocol between your server and your clients!
Obviously the server can send two types of messages "response" and "broadcast".
A rather simple approach is tagging your messages: e.g. prefix your mesages with "R" if it is a response to a request and with "B" if it is an unattended broadcast message. (This all depends how communication between server and clients is intended to be performed.)
Whether your client needs different threads for coping with the messages is a completly different story. Having different threads is useful if the processing activity within your client would prevent timely reads of the socket. Then you might consider having an I/O thread that is doing communications and is dispatching the messages to different "handlers" (could be other threads) for processing. (This I/O thread also can remove the tag such that existing processing code need not learn about the lower protocol with the server.)
An analogous reasoning might apply to your server side. Depending on the dynamics of interactions and processing of requests, you might use several threads. Then you should have one that is doing I/O with the clients and others that are doing the work (generating responses or broadcast messages)
When your clients connect to the server, your server creates a Socket for it, here it is Socket socket = ss.accept();, your socket variable will be holding that client.
now if you just keep adding your client socket to a arraylist in your while loop, you will have a list of clients actively connected with your server like:
after the accept:
clients = new ArrayList<DataOutputStream>();
Socket socket = ss.accept();
os = new DataOutputStream(socket.getOutputStream());
clients.add(os);
Now as you have all the clients in that clients arraylist, you can loop through it, or with some protocol define which client should i send the data after reading.

multiple InputReader for a single Socket

I have a java client/server program using ServerSocket/Socket.
In my client, I have a thread(call in ReceiverThread) which always waits for a incoming message from server. so it will block my InputReader (myInputReader.readObject()) .
In the client, there are also some threads, which send some stuff to the server and wait using (myInputReader.readObject()), until server responses. but in this case, if the server sends a response, there is a chance that the ReceiverThread catches the server response, which is not what i want.
Is there any way that i can have multiple InputStreams in a single Socket connection?
UPDATE: I have to use java Socket
It doesn't make sense to listen on a socket in 2 (or more) different threads simultaneously. What you need to do is have a single "entry point" for incoming data, and have that entry point understand the context of each data block (message) and spread that to what ever logical peace of code uses it. This is a general design pattern, not a java issue.

Java single-threaded multi-user chat program

So I'm working on this recreational project to learn more about java networking and so far every tutorial or documentation I've come across involves creating a new thread for each client connection to wait for input. I'm wondering if it's possible to handle the list of client connections with a single thread? I tried doing something like the following code but it didn't work.
while(true){
for(Client c : list){
DataInputStream dis = new DataInputStream(c.getSocket().getInputStream());
if(dis.readLine()!=null){
//Code
}
dis.close();
}
}
Yes it is possible with a single thread using the NIO package. This will allow you to set up non-blocking IO and multiplex across channels within your single thread. It's not exactly trivial but there's a decent example here.
Your example above will block on the readLine() call until data is available on the Socket. If one of your clients is waiting on data, the while loop will never proceed and you'll never service the other clients.

check if there are message incoming from clients in a Java server

I have a chat Java Server, actually it receive the client and insert his id into a deque and his id and socket into an hashmap. In an another thread the server iterate the deque and check if clients are sending message, in case the server manage it with some operatorion in a other thread. My "Problem" is that iterate the deque (or a list) is a slow operation, if i had milions of people connected it should iterate too many item. so i'm asking you if there's one better method to do this. here's the code of the bottle neck:
while(true){
String id = MainServer.deque_id.poll();
Socket socket = MainServer.map_socket.get(id);
if(new PushbackInputStream(socket.getInputStream()).available() > 0)
MainServer.queue_manage_message.put(new ManageMessageTask(id, socket, true));
MainServer.deque_id.addLast(id);
}
You don't need need to construct a PushbackInputStream just to call available() and then throw the stream away. All InputStreams have available(), although it doesn't work in all of them.
With blocking I/O you need at least one thread per connection, maybe two, one for input and one for output.
Or else you need to look into non-blocking and multiplexed I/O using Selectors and Channels. See the java.nio.channels package.

Multithread server program in Java

I am trying to write a multithread program in Java where a server listens for connections from clients and spawns a thread to acommodate each client. I have:
while(true)
{
Socket s = server.accept();
ClientHandler ch = new ClientHandler(s);
Thread t = new Thread(ch);
t.start();
}
My question is: whenever it accepts a connection in
Socket s = server.accept();
and starts executing the following lines of code to create the thread etc., what happens to a request for connection from a client during that time. Is it queued somehow and it will get served in the next loop of while(true) or will it be rejected?
thanks,
Nikos
After the accept() returns the TCP handshake is complete and you have a connected client socket (s in your code). Until the next call to accept() the OS queues pending connection requests.
You might want to check out some tutorial like this one for example.
I wrote a tiny http server in Java, which you can find on github. That might be a good example for you to take a look at real-world usage of Sockets and multithreading.
As it was answered already: yes it is queued and no it is not rejected.
I think that anyone reading this question should first know that when you instantiate a socket:
server = new ServerSocket(mPort, mNusers);
Java is already implementing a network socket ; which has clearly defined behavior. The connection will be rejected however after reaching the limit set.
Also, the code posted in the question accepts multiple connections but looses the refference for the previous. This may be a "duh" but just in case someone is copy-pasting , you should do something to store all the created sockets or handlers. Perhaps:
ClientHandler[] ch = new ClientHandler[mNusers];
int chIndex = 0;
while(true)
{
Socket s = server.accept();
ch[chIndex] = new ClientHandler(s);
Thread t = new Thread(ch);
t.start();
chIndex++;
}
An array may not be the best option but I want to point out that with sockets you should know what's the limit of connections you will allocate
ugh :)
there is a so called SYN-queue, which takes up to the requested amount of not yet established connections (there is a per call and a system-wide limit - not sure if its even user limited).
when "listening" on a ServerSocket, you specify that by - one of the answers says "Nusers" but it is - the size of the "backlog" the socket should keep. in this backlog the pending connections are stored and if it is filled up, all other (should) get a ConnectionRefused.
So
a) increase that when you are to slowly accepting (server.accept())
connections
b) accept the connections faster by
b.1) using a ThreadPool (be happy moving the problem to context-switches of the os)
b.2) use NIO and with that the ability to handle socket-states
within single threads/CPUs (as long as the internal data throughput is better than the one in the network, this is the more performant option)
have fun

Categories

Resources