Java server to handle multi-clients simultaneously - java

I am new to java server and client. I want to make a multi-client server. After making server code ready to accept more than one client it is like this :
Server code :
public class Server {
int clientNumber = 1;
ServerSocket mServer = new ServerSocket(9090);
try {
while (true) {
new TheServer(mServer.accept(), clientNumber++).start();
}
} finally {
mServer.close();
}
}
private static class TheServer extends Thread {
private Socket client;
private int clientNumber;
public TheServer(Socket client, int clientNumber) {
this.client = client;
this.clientNumber = clientNumber;
}
public void run() {
try {
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
dos.writeUTF(numberString);
while (true) {
String message = br.readLine();
dos.writeUTF(message);
}
} catch (IOException e) { }
}
}
The clients are added to the server as I expect.
If I have one client, the --- dos.writeUTF(message); --- give the desired result inside client console, so in server console I write down (A) and press enter, then the (A) is printed inside #1 Client, then I write down (B) in server console and press enter, then the (B) is printed inside #1 Client, it seems good.
But if the second client join the server, the result inside both clients console is hold for one time press and is fired on second enter press. To simplify : Inside server console I press (A) and press enter, nothing is happening on clients consoles, then I press (B) inside server console again, and now the first message (A) and second message (B) are printed one (A) inside #1 Client and one (B) inside #2 Client and this is not the behavior that I expect.
What I expect: When 2 Clients exist and server send message (A), I need all Clients (here there are 2 clients) get the message together. Imagine you are playing a game online, If I have a character (like a ball) and I move it inside a game field, all the other players have to see my character moving. I wish I was clear.
I think I have to make an array to keep the clients and send message to that array maybe...
So how can I solve it. If the client code is needed please tell me.

Look into something called the Publish-Subscribe pattern, also known as the Observer pattern, here is an example:
https://www.journaldev.com/1739/observer-design-pattern-in-java

Related

How to listen for a socket input without blocking other requests

My title is probably not the most descriptive, but I'm going to try and show as much code as possible in hope that it'll help everyone understand my question better. Here's how my client side of my project queries the server for information. This is an example of a typical request:
private String GENERATEGROUPKEY()
{
/* `out` is a PrintWriter using the sockets output stream */
out.println("GENERATEGROUPKEY");
try
{
/* `in` is a BufferedReader using the sockets input stream */
String response = in.readLine();
String[] temp = response.split(" ");
return temp[1];
}
catch (IOException ex)
{
return null; // throw connection error to client
}
}
My issue is that at any time, the server can send an unsolicited message to the client through that same socket with information (think about it like a chat client receiving a message). My unsuccessful idea was to create a thread that listens for such a message as long as we're not in the middle of another query, but that was also unsuccessful because even though I'm interrupting that thread, it's still hogging the messages that should've gone to the client query.
private String GENERATEGROUPKEY()
{
out.println("GENERATEGROUPKEY");
listenThread.interrupt(); // block listenThread from recieving response
try
{
String response = in.readLine();
String[] temp = response.split(" ");
listenThread = new PulseThread(in); // we're done, so allow
listenThread.start();
return temp[1];
}
catch (IOException ex)
{
listenThread = new PulseThread(in); // we're done, so allow
listenThread.start();
return null; // throw connection error to client
}
}
Here's exactly what listenThread is
public class PulseThread extends Thread
{
private BufferedReader in;
public PulseThread(BufferedReader in)
{
this.in = in;
}
#Override
public void run()
{
while (true)
{
if (Thread.currentThread().isInterrupted())
{
break;
}
try
{
String line = in.readLine();
System.out.println(line);
String[] params = line.split(" ");
if (params[0].equals("PULSED"))
{
NotificationManager.sendNotification("You have been pulsed!", "Pulsed by: " + params[1]);
}
}
catch (Exception ex)
{
}
}
}
}
I was previously under the impression that interrupting the thread in the middle of the BufferedReader's blocking call with readLine() would just cancel the blocking call unless I'm doing something else wrong.
Any help would be greatly appreciated, thanks.
EDIT: So looking into my assumption just a few lines above this sentence, it seems interrupting the thread doesn’t cancel readLine(). I guess the interrupting thread idea is a no-go. What’s the right way to do this?
The general pattern here is that you want one thread processing output from the socket (blocking while waiting) and then dispatching messages out to the correct things that requested them.
One implementation I like and have used successfully in multiple projects is to add a randomly generated ID to “requests” as part of a generic header (including a message type as well) and have the server always mirror the ID back in the response, which allows the client to associate a request with a response without caring what type of message it is.
In concrete terms, something like a SocketMessenger class with 2 public functions: sendRequest(type, body, callback) and registerUnsolicitedHandler(type, callback).
sendRequest builds the message header with type and a randomly generated ID, adds it to a list of pending replies alongside a reference to the callback function, and then sends the completed message to the server.
registerUnsolicitedHandler does what it’s name suggests and adds the callback function to a map of message types to be used when an incoming message has no ID.
In the separate thread handling incoming messages, it deserialises incoming data to get the type and ID from the header, if the message has an ID it searches the pending reply list and calls the appropriate callback with the message body (probably scheduled on the main thread, I’m glossing over some detail like locking), else it searches the unsolicited handler list for the specified type and calls that callback.

Why does the following code print null?

I am trying to make client-server connection. First I have executed server code in one console and then client code in another console. I want that after the client code runs, the client enters his name and then I will create the object of client socket class and print the name of client in the server console. But on the server console it prints null when I try to print the name of client.
Since accept() method of server class waits for the client socket object, so before this line System.out.println(Myclient1.nameOfClient + " connected"); gets executed, client would already have entered his name in String nameOfClient.
I am unable to understand the reason behind this.
Server code
public Myserver1() {
try {
ss = new ServerSocket(10);
while (true) {
s = ss.accept(); // waits for the client socket
System.out.println(Myclient1.nameOfClient + " connected"); // Here I want to print the name of client(Myclient1.java).
al.add(s);
Runnable r = new MyThread(s, al);
Thread t = new Thread(r);
t.start();
}
} catch(Exception e) {}
}
Client code
public Myclient1() {
System.out.println("enter ur name");
nameOfClient = new Scanner(System.in).nextLine(); // Here I am storing the name of client so that I can access nameOfClient from Myserver1.java
try {
s = new Socket("localhost", 10);
din = new DataInputStream(s.getInputStream());
dout = new DataOutputStream(s.getOutputStream());
clientchat();
} catch(Exception e) {}
}
Server and clients should run independently of each other, or else it defeats the purpose of networking.
Right now, you are accessing a static variable the has never been initalized because the client isnt running in the same process as the server.Send the name over a socket, and use that as your print and your problem will be fixed.

Client connects but cant send message to the server.[Console Chat]

I tried to make a console chat server. the main problem i am facing is that i can not send the message to the server.. as you can see in the img i uploaded that the server and the client are connected. but when i type anything in the client side. The client becomes unresponsive and i have to close the cmd prompt.
How can i fix this?
Is something wrong with my computer or is the code wrong?
public class MyClient
{
Socket s ;
DataInputStream din ;
DataOutputStream dout;
public MyClient()
{
try
{
s= new Socket("localhost",10);
System.out.println(s);
din = new DataInputStream(s.getInputStream());
dout= new DataOutputStream(s.getOutputStream());
ClientChat();
}
catch(Exception e)
{
System.err.println(e);
}
}
public void ClientChat() throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//Scanner s2 = new Scanner(System.in);
String s1;
System.out.println("start the conversation");
do
{
s1=br.readLine();
//s1=s2.nextLine();
dout.flush();
System.out.println("server:"+din.readUTF());
}
while(!s1.equals("stop"));
}
public static void main (String args[])
{
new MyClient();
}
}
The code snippet never calls dout.write*(), so nothing is ever sent over the Socket.
readLine() will block until a line of text is read, so messages sent to the client won't be printed until after the client types a 2nd line of text. You can fix this either by using asynchronous I/O or by moving the read loop into it's own Thread.
You need to make the server and client a thread, so they can work independently.
server as thread will wait for a client connections and will receive messages.
client as thread will work on its own.
problem is that they cannot run concurrently.
Use dout.writeUTF(s1); inside the do loop.
The writeUTF will allow you to write the subsequent message till then It will be stuck at readutf function.
The java.io.DataOuputStream.writeUTF(String str) method writes a string to the underlying output stream using modified UTF-8 encoding. Refer to this

Java Socket Chat Not Displaying All Messages

I am trying to work through a socket chat with just one client and the server. I have it successfully running, as in the server is capable of passing messages back and forth, but when I attempt to make the server side implementation a bit more complex, adding commands and such, that the client can use, the communication fails. It appears it might go out of sync even as using the same commands over and over again can produce different results, even though I flush everything after every command.
Example of simplistic output, this works as expected, every time:
Client:
import java.io.*;
import java.net.*;
public class Test1Client
{
public static void main(String args[])
{
InputStreamReader convert = new InputStreamReader(System.in);
BufferedReader stdin = new BufferedReader(convert);
try
{
Socket echoClient = new Socket("localhost", 17);
PrintStream outs = new PrintStream(echoClient.getOutputStream());
BufferedReader ins = new BufferedReader(new InputStreamReader(echoClient.getInputStream()));
while(true){
System.out.print("Type whatever you want: ");
String line = stdin.readLine();
outs.println(line);
System.out.println("Server says: " + ins.readLine());
}
}
catch (IOException e)
{
System.out.println(e);
}
}
}
Server:
import java.net.*;
import java.util.ArrayList;
import java.io.*;
public class Test1Server
{
public static void main(String args[])
{
try
{
ServerSocket socket= new ServerSocket(12167);
//Try not to use port number < 2000.
System.out.println("Waiting for a client to connect...");
Socket s = socket.accept();
System.out.println("Client Connected.");
BufferedReader ins = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintStream outs = new PrintStream(s.getOutputStream());
while (true)
{
String line = ins.readLine();
outs.println(line);
}
}
catch (IOException e)
{
e.getStackTrace();
}
}
}
I get output like this, it works every time just spitting it back out:
Type whatever you want: login
Server says: login
Type whatever you want: login
Server says: login
Type whatever you want: login
Server says: login
Type whatever you want: login
Server says: login
But when I make the server side a bit more complex by replacing its while(true) block with the following, I get a much more messy result:
String line = ins.readLine();
String response = manager.process(line);
outs.println(response);
outs.flush();
process:
msg= "User logged in successfully \n";
return msg;
You'll also notice some commented lines in the process command code. When I give back a simple message the server seems to keep up, but when I use the login function as well it gives the terrible output like this:
Type whatever you want: login ryanne
Server says: ryanne logged in successfully
Type whatever you want: login ryanne
Server says:
Type whatever you want: login ryanne
Server says: You may already be logged in or did not use correct username or password
Type whatever you want: login ryanne
Server says:
Type whatever you want: newuser jeff
Server says: You may already be logged in or did not use correct username or password
Type whatever you want: newuser jeff 12345
Server says:
Type whatever you want: new user jeff 12345
Server says: You may already be logged in or did not use correct username or password
Type whatever you want:
Again, notice the blanks where nothing comes back from the server, and then even the change in the commands does not prompt different responses. Its as if it went out of sync, just by using one additional function?
You have some "\n" at the end of some strings.
If you both put "\n" and use println, you will have double carriage returns, which will mess up your protocol. Remove the "\n"'s, and it should work better.
Maybe, data you sent was not flushed. Use outs.flush(); after outs.println(line); or change it's constructor call to PrintStream(echoClient.getOutputStream(),true); (enable auto-flush on printing new line)

ObjectInputStream - How to wait for new data?

I've got a client-server app I'm making and I'm having a bit of trouble when reading objects on the server.
After my server connects to a client socket, I build object input and output streams and pass them along to my service() method. In there, I'm supposed to handle different kinds of messages from the client. I can get a message from the client (that is, a Message object, of my design) just fine. But of course, what I want to do is have a loop so I can get a message, process it, and respond back.
So far, my code only works for a single message. When I added my loop, what happened was on every iteration, my server just kept reading the same message over and over again before my client got a chance to send a new message over the socket (I think this is what's happening, at least).
So what I really need to do is figure out how to make my service() method wait for new input. Any ideas? Or am I approaching this wrong? Do I need to create a new OIS on every iteration or...? Some code:
public void service(ObjectInputStream input, ObjectOutputStream output) throws IOException, Exception {
_shouldService = true;
while (_shouldService) {
// It just keeps reading the same message over and over
// I need it to wait here until the client sends a new message
// Unless I'm just approaching this all wrong!
NetworkMessage message = (NetworkMessage) input.readObject();
NetworkMessageHeader header = message.getHeader();
String headerType = header.getType();
if (headerType.equals(NetworkMessageHeader.NetworkMessageHeaderTypeConnect)) {
doLoginForMessage(message, output);
} else if (headerType.equals(NetworkMessageHeader.NetworkMessageHeaderTypeFiles)) {
doFilesList(message, output);
} else {
System.out.println("Unrecognized header type: " + headerType);
}
}
}
The ObjectOutputStream caches object representations and will not detect if you are resending the same instance over and over again from the client side, but with changes in it. If this is your scenario you need to call reset on the stream before each send.
NetworkMessage message = new NetworkMessage();
for(;;) {
message.setProperty(whatever);
oos.reset();
oos.writeObject(message);
}

Categories