ObjectInputStream[] using the method readObject() freezing the program - java

I'm quite new to java programming and tried doing a simple program where I have a server and 2 other users that can communicate by sending simple message (string). Everything works, but I have a problem when I use the readObject method. Basically, if the second user write a message before the first user, that message will not appear on the server screen until the first user send a message. It seems that the method readObject will freeze the program until it actually receives and object from that user, and will then continue :
while (true) {
message = (String) input[0].readObject();
showMessage(message);
message = (String) input[1].readObject();
showMessage(message);
}
My question is : is there a way to let the second user send an object before the first one if he's the first one to send something? Do I have to create a separate thread for each user? Thank you!

Related

JDA Discord bot, read last message of textchannel

I want that my Discord jda bot reads the last message of an textchannel after starting.
So I call :
textChannel.getHistory().getMessageById(config.getLatestMessageId());
The MessageHistory class doesn't have an getLatestMessage method somehow.
And for some reason textChannel.getHistory() is always empty and therefore always return null.
is there an other way to read messages (written before the bot was started).
Some aditional information:
The textchannel is the correct textchannel.
it is not empty, and I also tried writing new messages while the bot is active.
But the messagehistory is always empty.
Also something I find weird:
textchannel.gethistory().isempty() is true
and textchannel.hasLastMessage is true as well.
EDIT:
Do the following:
channel.getHistory().retrievePast(1).queue(messages -> {
// messages (list) contains all received messages
// Access them in here
// Use for example messages.get(0) to get the received message
// (messages is of type List)
});
// DON'T access the received messages outside here
// If you use queue the received messages WON'T be available directly after the call
PREVIOUS:
If I do the following on my bot it works:
channel.getHistory().retrievePast(1).queue(messages -> {
if (messages.size() > 0) System.out.println(messages.get(0).getContentDisplay());
});
After the call succeeded and the lambda is executed, calling
channel.getHistory().getRetrievedHistory()
should return the received chat history
You can also execute the action directly and block the current thread until the message history was received by doing the following:
MessageHistory h = channel.getHistory();
h.retrievePast(1).complete();
List<Message> ml = h.getRetrievedHistory();
if (ml.size() > 0) System.out.println(ml.get(0).getContentDisplay());
but I don't recommand doing this, since it will block the current thread. Use the code in the first part of my answer instead, which won't block execution, and will fill the message history with data and once its ready it will call the lambda.
Notice that I'm passing in 1 as an argument for the call to 'retrievePast'. This will only receive the last message send inside the text channel.
I guess you can't receive the entire text channel, since it would be to expensive to store all the sent data in the RAM or it would just take to long.

Issue with readLine() method

I am building a Chat system, where I need wait to get the User input (Sender) as well as to display the reply message (from receiver) at the same time.
So I am using a while loop for receiving and sending the messages:
while((text = inFromUser.readLine()) != null) //Msg from Sender
{
while((data_from_server=inFromServer.readLine()) != null) //Msg from receiver
{
System.out.println("Displaying Output=" + data_from_server);
System.out.println(data_from_server);
}
System.out.println("Getting Input=" + text);
outToserver.writeBytes(text + "\n");
}
My Problem is the client may send inputs again and again ,whereas the receiver may/may not send the reply back. But according to my logic, it's always expecting a input from the receiver and Vice Versa. Please suggest to fix this problem.
You're going to need more than one thread. Think about it - you have to wait until the user enters some data, and when that happens, display it immediately. You also have to wait until the server gives you some data, and display that immediately.
You can't wait for both at once; if you did, nothing would be displayed until both the user and the server had entered a line. You can't wait for one, then the other; if you did, the client couldn't read what they wrote until the server sent a message, or vice versa.
You need to wait for both at the same time, but running side-by-side. You want to perform an action as soon as either of them return something. This means you need to run a second thread. One thread waits for the user, and one thread waits for the server.

While loop not continuing - socket

Okay, so I'm creating a rather simple java application, which will eventually turn into an online 2-player texas hold'em game. Right now, I'm trying to send some simple messages over network to make sure the basic functionality is working. I am however stuck.
I've got two methods in a class. One for the serverside (or really a hybrid between a client and a server), and one for the clientside. They connect together fine. As I made this, I noticed that when I connected, they both spammed their default messages (right now being "CLIENT: Started" and "SERVER: Started" back and forth to eachother. I figured this was because the string containing that information was never emptied, and so they never knew when to stop transmitting it. I then made sure that after sending the message, that variable was nulled, and a check was made to see if it was null before sending.
Here's where it went wrong though! After doing that, they won't send more than one message at all. They send their respective welcome messages, but anything I try to transmit after that is ignored. It's almost like if the while-loop for the server/client stops.
So, I have two public variable declared in the class. These contain any message the server or client wishes to send.
public static String serverCommand = null;
public static String clientCommand = null;
They are null by default, but changed during runtime in the GUI-part.
The server loop looks like this:
while(true)
{
if((receive = receiveStream.readLine()) != null)
{
System.out.println(receive);
}
if(serverCommand != null)
{
printer.println(serverCommand);
printer.flush();
Network.serverCommand = null;
}
}
And the client while loop like this:
while(true)
{
if(Network.clientCommand != null)
{
printer.println(clientCommand);
printer.flush();
Network.clientCommand = null;
}
if((receive = receiveStream.readLine()) != null)
{
System.out.println(receive);
}
}
However, as mentioned - after Network.clientCommand is set to null the first time around, it never again sends any messages, even though Network.clientCommand changes due to user input during runtime.
I'll post two links to the complete sourcecode of the client/server-part of this below, as they're a bit too big to paste here.
LINK: http://hastebin.com/oqotirufic.java
Does anyone here have any idea what's happening, and how should I think when trying to fix/get around it? I'll add that my experience with both Java and network programming is very limited.
EDIT
I'll add the part of the GUI which acccesses/changes the variables.
http://hastebin.com/upadayuwug.java
Of course after Network.clientCommand is null, nothing more is sent — that's what you told it to do:
if((receive = receiveStream.readLine()) != null)
{
System.out.println(receive);
}
According to the JavaDoc, readLine() returns
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
Not "null if there's a pause in transmission". If it hasn't yet seen a full line, or the end of the stream (socket disconnection), well, then it's not done yet. It waits until it gets the full line of input before it goes to the next line of your code.
But how do you know if you should wait for a message to come in, or send out the next one? You can't. You can't depend on when or if anything will arrive from the other side.
What happens when both sides have nothing to send? They both start waiting to receive. What happens when one side gets something new to send? Well, once it receives something, it'll send it. But that never happens!
What you can do, is call readLine() in a separate thread. See the JavaDocs for Thread and the Java Tutorial Lesson "Concurrency". And if you're using Swing for your GUI, also see the Java Tutorial Lesson "Concurrency in Swing".

How do I communicate with all threads on a Multithreaded server?

Ok. I'm trying to grasp some multithreading Java concepts. I know how to set up a multiclient/server solution. The server will start a new thread for every connected client.
Conceptually like this...
The loop in Server.java:
while (true) {
Socket socket = serverSocket.accept();
System.out.println(socket.getInetAddress().getHostAddress() + " connected");
new ClientHandler(socket).start();
}
The ClientHandler.java loop is:
while(true)
{
try {
myString = (String) objectInputStream.readObject();
}
catch (ClassNotFoundException | IOException e) {
break;
}
System.out.println(myClientAddress + " sent " + myString);
try {
objectOutputStream.writeObject(someValueFromTheServer);
objectOutputStream.flush();
}
catch (IOException e) {
return;
}
}
This is just a concept to grasp the idea. Now, I want the server to be able to send the same object or data at the same time - to all clients.
So somehow I must get the Server to speak to every single thread. Let's say I want the server to generate random numbers with a certain time interval and send them to the clients.
Should I use properties in the Server that the threads can access? Is there a way to just call a method in the running threads from the main thread? I have no clue where to go from here.
Bonus question:
I have another problem too... Which might be hard to see in this code. But I want every client to be able to receive messages from the server AND send messages to the sever independently. Right now I can get the Client to stand and wait for my gui to give something to send. After sending, the Client will wait for the server to send something back that it will give to the gui. You can see that my ClientHandler has that problem too.
This means that while the Client is waiting for the server to send something it cannot send anything new to the server. Also, while the Client is waiting for the gui to give it something to send, it cannot receive from the server.
I have only made a server/client app that uses the server to process data it receives from the Client - and the it sends the processed data back.
Could anyone point me in any direction with this? I think I need help how to think conceptually there. Should I have two different ClientHandlers? One for the instream and one for the outstream? I fumbling in the dark here.
"Is there a way to just call a method in the running threads from the main thread?"
No.
One simple way to solve your problem would be to have the "server" thread send the broadcast to every client. Instead of simply creating new Client objects and letting them go (as in your example), it could keep all of the active Client objects in a collection. When it's time to send a broadcast message, it could iterate over all of the Client objects, and call a sendBroadcast() method on each one.
Of course, you would have to synchronize each client thread's use of a Client object outputStream with the server thread's use of the same stream. You also might have to deal with client connections that don't last forever (their Client objects must somehow be removed from the collection.)

Smack api and Java

I am using Tapestry 5, Smack api 3.1.0.
I have established a connection and am able to communicate with a user through the xmpp server but the replies i get are sent to the standard output as they come in:
Chat chat = connection.getChatManager().createChat("blah#jabber.org", new MessageListener() {
public void processMessage(Chat chat, Message message) {
// Print out any messages we get back to standard out.
System.out.println("Received message: " + message.getBody()); // this works
showonbrowser = message.getBody();
System.out.println(showonbrowser) // this prints nothing
}
};
I am looking to get the replies to my html file so i can read them on the web instead of the console. However, when i try to set message.getBody() to showonbrowser (a property on the page) i see no result. Does anyone know how I get around this?
Regards,
Kace
Smack is multi-threading and it has a nasty habit of eating up exceptions that are thrown (silently.) Most likely you are not using a thread-safe GUI and its throwing an exception that you never get.
I think the processMessage method is being called after the page is rendered.
You are creating a MessageListener instance (through an anonymous class), so you don't know when the processMessage method will be called. I think you would have to do something with AJAX to do partial updates on the page, polling the server and getting any new messages to show them on the page.

Categories

Resources