How can I read asynchronously from an inputstream? - java

I have a Socket with its input ad output stream. I want to use output synchronously and input asynchronously and store everything received without blocking the input.
Socket socket;
BufferedOutputStream outToServer;
DataInputStream inFromServer;
List<byte[]> incoming=ArrayList<byte[]>();
socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1",9100), 5000);
outToServer = new BufferedOutputStream(socket.getOutputStream());
inFromServer = new DataInputStream(socket.getInputStream());
How can I add an input listener to fill incoming list with incoming data?

Basically you want to look into the java.nio packages. There is full support for doing "async", "non-blocking IO" with standard java ... since quite some years.
See here for some examples. That tutorial basically starts with code as you have written in your question ... to transform that into "async".
But to be precise: you don't need to use "nio" or "nio2"; but if you are serious about turning into that direction, then nio/nio2 provide extremely helpful features.

There is no way to read InputStream asynchronously. You have to go where this InputStream is created, and access the source of data explicetly.

You need only to pass the InputStream to the Runnable that need to be executed asynchronously. This can be done for example in the constructor.
public class ConsumeInput implements Runnable {
private InputStream inputStream;
public ConsumInput(InputStream inputStream) {
this.inputStream = inputStream;
}
public void run() {
// Do something with inputStream
}
}
And in the main thread
...
ConsumeInput consumeInput = new ConsumeInput(inFromServer);
Thread t = new Thread(consumeInput);
t.start();
Obviously you can also use the new api to handle threads.
Note: this is only a skeleton code. You need to handle exceptions and closure of streams.

Related

OutputSteam is abstract

as the title says, getting the error "outputsteam is abstract". I'm new to Java so not quite sure how to go about solving it. My program is trying to send an arraylist of connections over a socket to a client, using this code;
public void sendList(Socket clientSocket, ArrayList connections) throws IOException
{
OutputStream outputStream = new OutputStream(clientSocket.getOutputStream(), true);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(connections);
System.out.println("List sent");
}
Thanks in advance!
The error message is telling you exactly what is wrong: You can't call a constructor on an abstract class, and instead will have to initiate one of the concrete subclasses of OutputStream. Perhaps a BufferedOutputStream that wraps your clientSocket OutputStream.
Why do you even have this line?
OutputStream outputStream = new OutputStream(clientSocket.getOutputStream(),
true);
Why not simply use directly use the OutputStream from the clientSocket?

How to handle sending multiple messages over a socket connection?

I'm a bit of a beginner programmer so it's possible this is quite obvious and I'm overlooking the answer. But on to the question.
I have a two-part program (its a little more complicated than this example, but the situation is the same). The program has multiple messages fired between the client and the server. I have a PrintWriter on the server-side to send messages to the client, and on the client, I have a BufferedReader to read the messages sent.
When this example is run, I'm given two lines as output. The first message is both messages, and the second is NULL. What I am wondering is if there is a way to basically halt the server until I am ready for the second message, so that I can do something on the client-side before the second message is sent.
I am hoping to not use Thread.Sleep, as I would rather the Server wait around until the Client says it is ready.
This is the client:
public class Client{
public void run(){
Socket socket = null;
InputStream in = null;
BufferedReader reader = null;
try{
socket = new socket("LocalHost",1234);
in = socket.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
}
String messageFromServer = "";
try{
messageFromServer=reader.readLine();
}
System.out.println(messageFromServer);
String messageFromServer = "";
try{
messageFromServer=reader.readLine();
}
System.out.println(messagefromServer);
//close everything
}
}
This is the server:
public class Server{
public void run(){
ServerSocket server = null;
Socket client = null;
try{
server = new ServerSocket(1234);
client = server.accept();
}
PrintWriter writer = null;
OutputStream out = null;
try{
out = client.getOutputStream();
writer = new PrintWriter(out, true);
}
writer.write("Hi I'm a server");
//do some stuff that takes some time, user input, etc. etc.
writer.write("I'm still a server");
//close everything
}
Thanks :)
The problem with the way you currently have you code is the fact that you are using a BufferedReader, but the server is not terminating it's messages with a new line.
When you close the writer, the client is reaching the EOF or EOS and unblocking the read so it appears that both strings are being sent at once...
If you do something like...
writer.write("Hi I'm a server\n");
// This will force the message to be written to the client and picked up ;)
writer.flush();
writer.write("I'm still a server\n");
writer.flush();
Then you will get the messages seperatly...
You can use ObjectInputStream to read Objects instead of Strings.
This way you will read only one Message(String in your case) every call to ObjectInputStream.readObject();
BTW you can read the first message, "do something" and then read the second message. you don't have to read all of the sent messages at once.
If there are no other messages, then your thread will be blocked when trying to read an object from the ObjectInputStream.
Use it like:
ObjectInputStream inputStream = new ObjectInputStream( socket.getInputStream() )

Confused About Reading and Writing From Input Streams (Sockets)

I have a question about reading and writing from input streams related to a socket. For instance, I have
ServerSocket testie = new ServerSocket(0);
Socket putClient = new Socket("localhost",testie.getLocalPort());
InputStream is = putClient.getInputStream();
OutputStream os = putClient.getOutputStream();
os.write("testt".getBytes());
System.out.println(convertStreamToString(is));
but "testt" is oddly never printed. The method convertStreamToString is from
Read/convert an InputStream to a String
public static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
Is there some flaw in my understanding of streams and sockets. I thought that if you wrote to a socket's output stream you can retrieve it from its input stream? The method just hangs indefinitely.
If you write to a socket's output stream you can read from the remote socket's input stream. In your code you are writing to one side of the socket and then trying to read from that same side.
Unfortunately, you haven't even created the remote socket yet. The next thing you will want to do is call accept() on the ServerSocket. This will receive the connection from putClient and create a Socket. This new socket will be the server side socket. Essentially you will have the following:
//Server Thread
ServerSocket testie = new ServerSocket(0);
Socket remoteSocket = testie.accept();
remoteIs = remoteSocket.getInputStream();
remoteOs = remoteSocket.getOutputStream();
System.out.println(new Scanner(remoteIs).next());
//Client Thread
Socket putClient = new Socket("localhost",testie.getLocalPort());
InputStream is = putClient.getInputStream();
OutputStream os = putClient.getOutputStream();
os.write("testt\n".getBytes());
os.flush();
Notice that I said two different threads. The problem is that the call testie.accept() will block until it gets a connection. But also, new Socket("localhost",testie.getLocalPort()) will block until the connection is established. These calls can't be made on the same thread.
UPDATE:
It's probably worth pointing out that I'm not very confident in that convertStringToStream method. You might want to start with something simple like what I've fixed the above to (note the newline in the write call).

How to gunzip data on the fly as i'm reading it from an InputStream to an OutputStream?

I have a large InputStream containing gzipped data.
I cannot modify the data in the InputStream directly. Code that uses this InputStream later on expects unmodified, compressed data. I could swap out the InputStream with a new InputStream if needed, but the data must remain compressed.
I need to print out the uncompressed contents of the InputStream as I go for debugging purposes.
What is the simplest way to print the uncompressed data in my InputStream to a PrintStream, without irrevocably uncompressing the InputStream itself and without reading the whole thing into memory?
Here's how I did it.
// http://stackoverflow.com/a/12107486/82156
public static InputStream wrapInputStreamAndCopyToOutputStream(InputStream in, final boolean gzipped, final OutputStream out) throws IOException {
// Create a tee-splitter for the other reader.
final PipedInputStream inCopy = new PipedInputStream();
final TeeInputStream inWrapper = new TeeInputStream(in, new PipedOutputStream(inCopy));
new Thread(Thread.currentThread().getName() + "-log-writer") {
#Override
public void run() {
try {
IOUtils.copy(gzipped ? new GZIPInputStream(inCopy) : inCopy, new BufferedOutputStream(out));
} catch (IOException e) {
Log.e(TAG, e);
}
}
}.start();
return inWrapper;
}
This method wraps the original InputStream and returns the wrapper, which you'll need to use from now on (don't use the original InputStream). It then uses an Apache Commons TeeInputStream to copy data to a PipedOutputStream using a thread, optionally decompressing it along the way.
To use, simply do something like the following:
InputStream inputStream = ...; // your original inputstream
inputStream = wrapInputStreamAndCopyToOutputStream(inputStream,true,System.out); // wrap your inputStream and copy the data to System.out
doSomethingWithInputStream(inputStream); // Consume the wrapped InputStream like you were already going to do
The background thread will stick around until the foreground thread consumes the entire input stream, buffering the output in chunks and periodically writing it to System.out until it's all done.

ObjectOutputStream and PrintWriter Conflict

I have server and client set up, which is basically a basic text email system. I am currently using a PrintWriter to send the text between the server and client. I am trying to create a attachment based system and to do this I am using a ObjectOutputStream.
private static PrintWriter output;
private static ObjectOutputStream outStream;
public ClientHandler(Socket socket) throws IOException
{
client = socket;
outStream = new ObjectOutputStream(client.getOutputStream());
input = new Scanner(client.getInputStream());
output = new PrintWriter(client.getOutputStream(), true);
}
I currently have the problem where if I try send text via the output printwriter, for some reason extra characters will be added to the beginning of the text that is sent, meaning the program cannot identify key words being passed via the printwriter to the client. The problem will stop if i comment out the creation of the outStream object.
Can anyone give me any advice to try solve this problem of conflict?
This extra text is coming from the object output stream.
Attaching an ObjectOutputStream AND a PrintStream to the same outputstream is basically just never going to work. You have to come up with a solution for using 1 or the other. To use just a PrintStream, you might consider converting your object(s) to JSON or XML. On the other hand, you could just use an ObjectOutputStream and write your strings to the ObjectOutputStream
ObjectOutputStream should only be used as an ObjectOutputStream on that channel. Use the PrintWriter on another socket if you really need it.
Extend your ClientHandler and overwrite the constructor to include code for handling file transfers. Have two ports open, one for text and another for file transfers.
private static PrintWriter output;
public ClientHandler(Socket socket) throws IOException
{
client = socket;
input = new Scanner(client.getInputStream());
output = new PrintWriter(client.getOutputStream(), true);
}
private static ObjectOutputStream outStream;
public ClientFileHandler(Socket socket) extends ClientHandler throws IOException
{
client = socket;
outStream = new ObjectOutputStream(client.getOutputStream());
}

Categories

Resources