I am trying to understand some things about threads in java, which I am very unfamiliar with. Unfortunately my example is too big for running code, but I'll try to specify my problem as well as possible.
One of two similar code segments (taken from a little example which features a simple ChatClient/Server class), which are the center of my question:
public void run(){
String message;
try{
while((message = reader.readLine()) != null){
tellEveryone(message);
}
}catch(Exception ex){...}
}
(Taken from an inner class of the Server class.)
The server is waiting in a while(true) loop for clients via its serversockets accept() method and whenever a client connects, a new Thread is started with the above run method as "entry point".
What I don't understand is why this works. My understanding until now was that Thread which is supposed to constantly listen to something has to contain a while(true) construct because otherwise it would just finish it's run method and it would be finished with no return ("dead" call stack).
So for my example when reader gave us all lines he had to give in the beginning, I supposed it would leave the run()-method and nothing would happen when the specific client would send a new message but it seems it stays listening for client input. How does that work?
(I probably should say that "reader" is a BufferedReader within the inner class which is instantiated once for every connected client.)
I hope that was sufficiently explained. If more Information is needed I will gladly provide it.
readLine() blocks while there is no data. It only returns null at end of stream, which in the case of a socket means that the peer has disconnected.
If the client does not send anything, the server socket does not have anything to read. When the client writes to the socket and the contents are sent the reader can read the contents
Related
I'm developing a distributed system that receives requests via Socket and writes the results back using OutputStream.
I'm facing problems because I have to return a very large string, but Java just keeps the execution of the code after I call the method print() without it finished printing:
public void attendRequisition(Socket clientSocket) {
PrintWriter pw = new PrintWriter(clientSocket.getOutputStream());
pw.print(getResults());
pw.close()
}
Some information:
I need to close the connection after sending the results.
Without the close() instruction, the whole printing process takes about 3~5 seconds to finishes
I'm using telnet to test this method, and I can see the message coming and being cut becase of Java running the close() instruction
I can't count with receiving client's feedback
I believe this is happening because Java thinks the method print() finished executing, but what might be happening is that Java sends the message to the JVM, and JVM send it to the network adapter, and since the message is very large, close() method is called before the network adapter is able to send the entire message.
What I need is a way to make sure Java will only run the instruction close() after the printing process finished and the client received the entire message.
UPDATE: I was able to get it working properly by adding a Thread.sleep(). By doing this, the SO has enough time to send the message before Java closes the connection. But I don't want to use this solution, it implicates on too many problems.
I was able to solve the problem using DataOutputStream.writeBytes(). This way, the execution only continues when the method finishes sending the data. It is slower, but works.
I'll bet that if you use another constructor (i.e., the one whose 2nd argument is a boolean to indicate your desire to flush) then your example will work. The way you're constructing the object, autoflush is disabled.
If your real code is more complex, then you can call pw.flush() at the appropriate moments.
I can see the message coming and being cut becase of Java running the close() instruction
No you can't. You can see the message being cut, unless you're wrong about how long it is, but you're jumping to conclusions about the reason. Java does not close the PrintWriter before it has finished sending. It flushes the writer to the socket send buffer, blocking if necessary, and then closes the underlying socket, which buffers a FIN behind the data. All the data gets sent, and all the data gets received, before the FIN arrives, which signals end of stream to the receiver.
Possibly you are unaware that PrintWriter swallows exceptions and therefore should really not be used over a network.
I'm pretty sure that's as titlegore as you can get, but let me try and explain: I'm trying to create a pretty simple online multiplayer game with a chatroom attached. Both the chatroom section and game section need to see the data coming from the server so they can handle data meant for them.
The two classes reading in the socket are ChatClient and Gameboard. They both implement Runnable and are running on separate threads.
Inside the run() function of each of the classes I have the following code:
try {
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String line = in.readLine();
if(line != null) { ...
This works perfectly fine when only one of them exists. The second the other thread starts up only the second one actually gets any of the socket's input stream, but I'm not sure why. From my understanding of the code the two BufferedReaders should be completely independent, meaning I'm not sure why they're interfering with one another. Can I get some help?
Wrong approach: you do not use two threads to read input from the same socket. I would be rather surprised if that is at all possible.
You have one thread reading that socket, and either that thread decides where to send that data to (like in: deciding which specific sink a line should go to); or it simply copies the data and sends it to all known sinks.
From my understanding of the code the two BufferedReaders should be completely independent
Impossible. They are both reading from the same socket, which is already a problem, and they are both buffered, meaning they are liable to buffer data intended for the other thread, whatever that means. You can't do this.
I'm trying to make a server socket to listen to a client input stream but when i execute the start_listening() method, my program gets stuck. I even tried to remove the loop, but i still have the same problem. i guess that it waits for the client interaction. is there an alternative way to listen while the program is also working?
public static void start_listening(){
listener = new ServerSocket(9090);
while (true) {
Socket socket = listener.accept();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
us = (User) in.readObject();
}
}
When using the sockets technique, accept() blocks the execution of the current thread until a client connects to the listening socket. This is a defined behavior. Java documentation says: "The method [accept()] blocks until a connection is made." Have the server run within a endless loop can be ok.
So, to get this whole thing run you might want to take a look at this socket example which uses threads. Inside the run() method of ConnectionHandler you would deal with your User object.
Besides that the loop never ends (I suppose you will break at some point), you should do that kind of stuff in a separate Thread or an AsyncTask, doing accept in the main thread makes Andriod freeze until somebody connects to the socket. That's why your program gets stuck.
You might just use a Boolean flag to indicate when to end the while loop.Other wise the loop keep iteration as it never breaks.
while (true) { //will it ever breaks ??
}
First off, if you helped me solve my problem with reading an undefined length HTTP response, I'd like to thank you. I took your advice and switched from HTTP responses to raw Java sockets. But I'm having a little problem with this too.
The nature of a push server is to push things to the client as they are recieved (in my case the system uses a file labeled with the device id.) The problem is that with the KnockKnock example on the Java Tutorials, their code:
while ((inputLine = in.readLine()) != null) {...
Waits for the client to send something before sending something itself. So I decided to use:
while (true) {
if ((inputLine=in.readLine())==null) inputLine="";
...
If any of the input interpereters get this empty string, then they won't do anything.
My Question essentially is which one is better and, if it's the first one, how can I keep checking the file to send out what is required without spawning a thread?
The first one implements the protocol imagined for the KnockKnock example: a client sends "KnockKnock", and the server answers.
The second one doesn't make much sense. If the client has a an output stream open with the server, and the server calls readLine(), it means that it's waiting for a line to come from the client. And the call will block until the client sends a line, or closes the socket.
It seems you don't expect any input from the client. In this case, well, don't open an input stream at all, and don't call readLine() on the input stream (obviously). Send what you need to send to the client directly, as soon as you want to send it.
I am currently trying to write a very simple chat application to introduce myself to java socket programming and multithreading. It consists of 2 modules, a psuedo-server and a psuedo-client, however my design has lead me to believe that I'm trying to implement an impossible concept.
The Server
The server waits on localhost port 4000 for a connection, and when it receives one, it starts 2 threads, a listener thread and a speaker thread. The speaker thread constantly waits for user input to the console, and sends it to the client when it receives said input. The listener thread blocks to the ObjectInputStream of the socket for any messages sent by the client, and then prints the message to the console.
The Client
The client connects the user to the server on port 4000, and then starts 2 threads, a listener and s speaker. These threads have the same functionality as the server's threads, but, for obvious reasons, handle input/output in the opposite way.
The First Problem
The problem I am running into is that in order to end the chat, a user must type "Bye". Now, since my threads have been looped to block for input:
while(connected()){
//block for input
//do something with this input
//determine if the connection still exists (was the message "Bye"?)
}
Then it becomes a really interesting scenario when trying to exit the application. If the client types "Bye", then it returns the sending thread and the thread that listened for the "Bye" on the server also returns. This leaves us with the problem that the client-side listener and the server-side speaker do not know that "Bye" has been typed, and thus continue execution.
I resolved this issue by creating a class Synchronizer that holds a boolean variable that both threads access in a synchronized manner:
public class Synchronizer {
boolean chatting;
public Synchronizer(){
chatting = true;
onChatStatusChanged();
}
synchronized void stopChatting(){
chatting = false;
onChatStatusChanged();
}
synchronized boolean chatting(){
return chatting;
}
public void onChatStatusChanged(){
System.out.println("Chat status changed!: " + chatting);
}
}
I then passed the same instance of this class into the thread as it was created. There was still one issue though.
The Second Problem
This is where I deduced that what I am trying to do is impossible using the methods I am currently employing. Given that one user has to type "Bye" to exit the chat, the other 2 threads that aren't being utilized still go on to pass the check for a connection and begin blocking for I/O. While they are blocking, the original 2 threads realize that the connection has been terminated, but even though they change the boolean value, the other 2 threads have already passed the check, and are already blocking for I/O.
This means that even though you will terminate the thread on the next iteration of the loop, you will still be trying to receive input from the other threads that have been properly terminated. This lead me to my final conclusion and question.
My Question
Is it possible to asynchronously receive and send data in the manner which I am trying to do? (2 threads per client/server that both block for I/O) Or must I send a heartbeat every few milliseconds back and forth between the server and client that requests for any new data and use this heartbeat to determine a disconnect?
The problem seems to reside in the fact that my threads are blocking for I/O before they realize that the partner thread has disconnected. This leads to the main issue, how would you then asynchronously stop a thread blocking for I/O?
I feel as though this is something that should be able to be done as the behavior is seen throughout social media.
Any clarification or advice would be greatly appreciated!
I don't know Java, but if it has threads, the ability to invoke functions on threads, and the ability to kill threads, then even if it doesn't have tasks, you can add tasks, which is all you need to start building your own ASync interface.
For that matter, if you can kill threads, then the exiting threads could just kill the other threads.
Also, a "Bye" (or some other code) should be sent in any case where the window is closing and the connection is open - If Java has Events, and the window you're using has a Close event, then that's the place to put it.
Alternately, you could test for a valid/open window, and send the "Bye" if the window is invalid/closed. Think of that like a poor mans' event handler.
Also, make sure you know how to (and have permission to) manually add exceptions to your networks' firewall(s).
Also, always test it over a live network. Just because it works in a loopback, doesn't mean it'll work over the network. Although you probably already know that.
Just to clarify for anyone who might stumble upon this post in the future, I ended up solving this problem by tweaking the syntax of my threads a bit. First of all, I had to remove my old threads, and replace them with AsyncSender and AsyncReader, respectively. These threads constantly send and receive regardless of user input. When there is no user input, it simply sends/receives a blank string and only prints it to the console if it is anything but a blank string.
The Workaround
try{
if((obj = in.readObject()) != null){
if(obj instanceof String)
output = (String) obj;
if(output.equalsIgnoreCase("Bye"))
s.stop();
}
}
catch(ClassNotFoundException e){
e.printStackTrace();
}
catch(IOException e){
e.printStackTrace();
}
In this iteration of the receiver thread, it does not block for input, but rather tests if the object read was null (no object was in the stream). The same is done in the sender thread.
This successfully bypasses the problem of having to stop a thread that is blocking for I/O.
Note that there are still other ways to work around this issue, such as using the InterruptableChannel.