I have a component that's given me data in an output stream (ByteArrayOutputStream) and I need to write this into a blob field of a SQL database without creating temp buffers hence the need to get an input stream.
Based on answers here and here I came up the following method to get an input stream from an output stream:
private PipedInputStream getInputStream(ByteArrayOutputStream outputStream) throws InterruptedException
{
PipedInputStream pipedInStream = new PipedInputStream();
Thread copyThread = new Thread(new CopyStreamHelper(outputStream, pipedInStream));
copyThread.start();
// Wait for copy to complete
copyThread.join();
return pipedInStream;
}
class CopyStreamHelper implements Runnable
{
private ByteArrayOutputStream outStream;
private PipedInputStream pipedInStream;
public CopyStreamHelper (ByteArrayOutputStream _outStream, PipedInputStream _pipedInStream)
{
outStream = _outStream;
pipedInStream = _pipedInStream;
}
public void run()
{
PipedOutputStream pipedOutStream = null;
try
{
// write the original OutputStream to the PipedOutputStream
pipedOutStream = new PipedOutputStream(pipedInStream);
outStream.writeTo(pipedOutStream);
}
catch (IOException e)
{
// logging and exception handling should go here
}
finally
{
IOUtils.closeQuietly(pipedOutStream);
}
}
}
Please note that the output stream already contains the written data and it can run up to 1-2 MB.
However regardless of trying to do this in two separate threads or the same thread I am finding that always PipedInputStream hangs at the following:
Object.wait(long) line: not available [native method]
PipedInputStream.awaitSpace() line: not available
You are overcomplicating the solution
ByteArrayOutputStream baos = ...;
byte[] data = baos.toByteArray();
return new ByteArrayInputStream(data);
I have worked out a very simple demo for use of PipedInput/OutputStream. It may or may not fit your usecase.
A producing class writing into PipedOutputStream:
public class Producer implements Runnable {
private final PipedOutputStream pipedOutputStream;
private final PipedInputStream pipedInputStream;
public Producer() throws IOException {
this.pipedOutputStream = new PipedOutputStream();
this.pipedInputStream = new PipedInputStream(pipedOutputStream);
}
public PipedInputStream getPipedInputStream() {
return pipedInputStream;
}
#Override
public void run() {
try(InputStream inputStream = ByteStreams.limit(new RandomInputStream(), 100000)) {
// guava copy function
ByteStreams.copy(inputStream, pipedOutputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
pipedOutputStream.close();
} catch (IOException e) {
// no-op
}
}
}
public static void main(String[] args) throws IOException {
try {
Producer producer = new Producer();
Consumer consumer = new Consumer(producer);
Thread thread1 = new Thread(producer);
Thread thread2 = new Thread(consumer);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
A consumer just counting the bytes:
public class Consumer implements Runnable {
private final Producer producer;
public Consumer(Producer producer) {
this.producer = producer;
}
#Override
public void run() {
try (PipedInputStream pipedInputStream = producer.getPipedInputStream()) {
int counter = 0;
while (pipedInputStream.read() != -1) {
counter++;
}
System.out.println(counter);
} catch (IOException e) {
e.printStackTrace();
}
}
}
At some level there has to be a buffer. See Connecting an input stream to an outputstream.
My favorite answer from there is from Dean Hiller:
void feedInputToOutput(InputStream in, OutputStream out) {
IOUtils.copy(in, out);
}
See the api for details
Related
This question already has answers here:
Why are empty catch blocks a bad idea? [closed]
(20 answers)
Closed 5 years ago.
I have 3 very small classes.
The main class:
import java.io.*;
public class ConnectionManager {
public static void main(String argv[]) {
try {
PipedOutputStream pout = new PipedOutputStream();
PipedInputStream pin = new PipedInputStream(pout);
Sender s = new Sender(pout, true);
Receiver r = new Receiver(pin, true);
System.out.println("Starting threads");
s.start();
r.start();
} catch (Exception e) {}
}
}
The Sender class
import java.io.*;
import java.util.Random;
public class Sender extends Thread {
ObjectOutputStream oos;
boolean primitive;
public Sender(OutputStream os, boolean primitive) {
try {
oos = new ObjectOutputStream(os);
} catch (Exception e) {}
this.primitive = primitive;
}
public void run() {
Random rand = new Random();
while (true) {
try {
System.out.println("Integer is being sent");
oos.writeInt(10);
Thread.sleep(1000);
} catch (Exception e) {}
}
}
}
And the Receiver class
import java.io.*;
public class Receiver extends Thread {
ObjectInputStream ois;
boolean primitive;
public Receiver(InputStream is, boolean primitive) {
try {
ois = new ObjectInputStream(is);
} catch (Exception e) {}
this.primitive = primitive;
}
public void run() {
System.out.println("Receiver is starting");
while (true) {
try {
int x = ois.readInt();
System.out.print("An int was read: " + x);
} catch (Exception e) {}
}
}
}
Please ignore seemingly unused variables like primitive and rand. They're holdovers from slightly different versions that I was testing out earlier and I was too lazy to remove them.
Anyway, when I run the main method in ConnectionManager, I get this as output:
Starting threads
Receiver is starting
Integer is being sent
Integer is being sent
Integer is being sent
Integer is being sent
Integer is being sent
Integer is being sent
Integer is being sent
Integer is being sent
//... ad infinitum
Why is the receiver thread not getting the messages that are piped through? What am I missing here?
In your code, there is an exception like java.io.IOException: Read end dead.
You are NOT able to spot because you are suppressing them with empty catch blocks.
The main point is that you need to change Sender and Receiver classes to use PipedOutputStream and PipedInputStream as shown below :
Sender class:
public class Sender extends Thread {
PipedOutputStream oos;
public Sender(PipedOutputStream os) {
try {
this.oos = os;
} catch (Exception e) {System.out.println(e);}
}
public void run() {
try {
System.out.println("Integer is being sent");
oos.write(10);
oos.close();
Thread.sleep(1000);
} catch (Exception e) {System.out.println(e);}
}
}
Receiver class:
public class Receiver extends Thread {
PipedInputStream ois;
public Receiver(PipedInputStream is) {
try {
this.ois = is;
} catch (Exception e) {System.out.println(e);}
}
public void run() {
System.out.println("Receiver is starting");
try {
int x = ois.read();
System.out.print("An int was read: " + x);
} catch (Exception e) {System.out.println(e);}
}
}
main() method:
public static void main(String[] args) throws Exception {
try {
PipedOutputStream pout = new PipedOutputStream();
PipedInputStream pin = new PipedInputStream(pout);
Sender s = new Sender(pout);
Receiver r = new Receiver(pin);
System.out.println("Starting threads");
s.start();
r.start();
} catch (Exception e) {
System.out.println(e);
}
}
OUTPUT:
Starting threads
Receiver is starting
Integer is being sent
An int was read: 10
As a side note, remember that, empty catch blocks are very bad practice as they hide the exceptions, so I strongly suggest not to use them in the code.
I got a very strange behaviour by reading bytes from the input stream of a socket.
In my project clients does requests to a service. For each request a new connection will be established.
At first the bytes are send that tells the service what kind of request will follow.
Then the request itself is send.
The service receives the bytes and proceeds the request. This does work for at least 95% of all request. For the remaining 5% there is a strange behaviour that i can not figure out.
The bytes are not all the bytes that got sended. But the most strange matter on this topic is that the missing bytes are not at the start or at the end of the stream. They are spread through the entire stream.
Sadly i can not provide the full code here cause it is work related. But i can provide the test code that shows the issue itself.
To figure out what is going on i wrote 2 classes. One derives from java.net.Socket and the other one from java.net.ServerSocket.
Here the code:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class DebugSocket extends Socket
{
private class InputStreamWrapper extends InputStream
{
private int
availables,
closes,
marksupporteds,
resets;
private List<Integer>
marks = new ArrayList<Integer>(),
reads = new ArrayList<Integer>();
private List<Long>
skips = new ArrayList<Long>();
#Override
public int available() throws IOException
{
availables++;
return DebugSocket.this.origininput.available();
}
#Override
public void close() throws IOException
{
closes++;
DebugSocket.this.origininput.close();
}
#Override
public synchronized void mark(int readlimit)
{
marks.add(readlimit);
DebugSocket.this.origininput.mark(readlimit);
}
#Override
public boolean markSupported()
{
marksupporteds++;
return DebugSocket.this.origininput.markSupported();
}
#Override
public synchronized void reset() throws IOException
{
resets++;
DebugSocket.this.origininput.reset();
}
#Override
public int read() throws IOException
{
int read = DebugSocket.this.origininput.read();
reads.add(read);
if ( read != -1 )
{
DebugSocket.this.inputdebugbuffer.write(read);
}
return read;
}
#Override
public int read(byte[] b) throws IOException
{
int read = DebugSocket.this.origininput.read(b);
DebugSocket.this.inputdebugbuffer.write(b, 0, read);
return read;
}
#Override
public int read(byte[] b, int off, int len) throws IOException
{
int read = DebugSocket.this.origininput.read(b, off, len);
DebugSocket.this.inputdebugbuffer.write(b, off, read);
return read;
}
#Override
public long skip(long n) throws IOException
{
long skipped = DebugSocket.this.origininput.skip(n);
skips.add(skipped);
return skipped;
}
}
private class OutputStreamWrapper extends OutputStream
{
private int
flushes,
closes;
#Override
public void close() throws IOException
{
closes++;
DebugSocket.this.originoutput.close();
}
#Override
public void flush() throws IOException
{
flushes++;
DebugSocket.this.originoutput.flush();
}
#Override
public void write(int b) throws IOException
{
DebugSocket.this.outputdebugbuffer.write(b);
DebugSocket.this.originoutput.write(b);
DebugSocket.this.originoutput.flush();
}
#Override
public void write(byte[] b) throws IOException
{
DebugSocket.this.outputdebugbuffer.write(b);
DebugSocket.this.originoutput.write(b);
DebugSocket.this.originoutput.flush();
}
#Override
public void write(byte[] b, int off, int len) throws IOException
{
DebugSocket.this.outputdebugbuffer.write(b, off, len);
DebugSocket.this.originoutput.write(b, off, len);
DebugSocket.this.originoutput.flush();
}
}
private static final Object
staticsynch = new Object();
private static long
idcounter = 0;
private final long
id;
private final ByteArrayOutputStream
inputdebugbuffer,
outputdebugbuffer;
private final InputStream
inputwrapper;
private final OutputStream
outputwrapper;
private InputStream
origininput;
private OutputStream
originoutput;
public InputStream getInputStream() throws IOException
{
if ( origininput == null )
{
synchronized ( inputdebugbuffer )
{
if ( origininput == null )
{
origininput = super.getInputStream();
}
}
}
return inputwrapper;
}
public OutputStream getOutputStream() throws IOException
{
if ( originoutput == null )
{
synchronized ( outputdebugbuffer )
{
if ( originoutput == null )
{
originoutput = super.getOutputStream();
}
}
}
return outputwrapper;
}
public DebugSocket()
{
id = getNextId();
inputwrapper = new InputStreamWrapper();
outputwrapper = new OutputStreamWrapper();
inputdebugbuffer = new ByteArrayOutputStream();
outputdebugbuffer = new ByteArrayOutputStream();
}
private static long getNextId()
{
synchronized ( staticsynch )
{
return ++idcounter;
}
}
}
import java.io.IOException;
import java.net.ServerSocket;
public class DebugServerSocket extends ServerSocket
{
public DebugServerSocket() throws IOException
{
super();
}
public DebugSocket accept() throws IOException
{
DebugSocket s = new DebugSocket();
implAccept(s);
return s;
}
}
The class DebugSocket takes notification of each interaction with the InputStream as well as OutputStream
Now when the issue occurs i always can see that bytes are missing.
Here an example:
The client send 1758 bytes. I got the 23 top bytes from the member outputdebugbuffer in the DebugSocket.
Bytes: 0,0,0,0,0,0,0,2,0,0,6,-46,31,-117,8,0,0,0,0,0,0,0,-83
The server received 227 Bytes. For debug issues i always do read the input stream till i get a -1, so that all bytes got proceeded. Now the 16 leading bytes on serverside that i got from the member inputdebugbuffer in the DebugSocket.
Bytes: 0,0,0,6,-46,31,-117,8,0,0,0,0,0,0,0,-83
As shown there are 7 bytes missing. the first 8 bytes are a long value this one i changed to a byte value for debugging. So i figured that the first byte is always correct.
If it were a failure in the code no request would be proceeded but as i said before this happens only to 5% of all connections at best.
Got anyone an idea whats going on here?
I also used the DataInputStream and DataOutputStream to send the data. I always flush after each write operation as you can see in the OutputStreamWrapper of the DebugSocket.
Do i miss something here?
If some other code is required i will try to post it.
P.S. The service is multi threaded and processes 100 request parallel. Also the clients are multi threaded and do 20 requests parallel. As said each request uses its one connection and closes this one right after the request got proceeded.
I hope someone got an idea on this matter.
Edit:
There is no main method to show that does anything like asked in the comments but here the the code blocks of the client and the server that are used.
Client: (Run parallel in 20 threads)
public void sendRequest(long _requesttype, byte[] _bytes)
{
Socket socket = null;
DataInputStream input = null;
DataOutputStream output = null;
InputStream sinput = null;
OutputStream soutput = null;
try
{
socket = new DebugSocket();
socket.connect(serveraddress);
sinput = socket.getInputStream();
soutput = socket.getOutputStream();
input = new DataInputStream(sinput);
output = new DataOutputStream(soutput);
output.writeLong(_requesttype);
output.flush();
soutput.flush();
output.write(_bytes);
output.flush();
soutput.flush();
// wait for notification byte that service had received all data.
input.readByte();
}
catch (IOException ex)
{
LogHelper.log(ex);
}
catch (Error err)
{
throw err;
}
finally
{
output.flush();
soutput.flush();
input.close();
output.close();
finishSocket(socket);
}
}
Server: (Run in a thread for each request. Up to 100 threads)
public void proceedRequest(DebugSocket _socket)
{
DataInputStream input = null;
DataOutputStream output = null;
InputStream sinput = null;
OutputStream soutput = null;
try
{
sinput = _socket.getInputStream();
soutput = _socket.getOutputStream();
input = new DataInputStream(sinput);
output = new DataOutputStream(soutput);
RequestHelper.proceed(input.readLong(), input, output);
// send notification byte to the client.
output.writeByte(1);
output.flush();
soutput.flush();
}
catch (IOException ex)
{
LogHelper.log(ex);
}
catch (Error err)
{
throw err;
}
finally
{
output.flush();
soutput.flush();
input.close();
output.close();
}
}
In the server code the readLong() already fails cause of the missing bytes.
Ok im done with all possible ways to locate the cause. From my experience with socket programming and parallel processing i can say that there is no bug in the code itself. Sniffers as well tell me that. Something on my machine is messing with the transmission.
I deactivated all i could think of (firewall/antivir/malware scanner) but no effect.
Got someone an idea what else could mess with tcp packages?
Edit:
Ok i got it. AVG 2014 is messing. Jetzt deactivating the components did not work. In Options->Settings there is a menu point were you can deactivate the AVG-Protection.
Got someone knowledge on this topic?
My guess is there is a bug somewhere else in the code. I copied the DebugSocket class from the question and created a MCVE (see below). It works fine, I was unable to reproduce the "server cannot read long-value" problem. Try modifying the code below to include more of the your own code until you can reproduce the problem, that should give you an idea where to look for the underlying cause.
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class TestDebugSocket implements Runnable, Closeable {
public static void main(String[] args) {
TestDebugSocket m = new TestDebugSocket();
try {
m.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
m.close();
}
}
final int clients = 20;
final boolean useDebugSocket = true;
final byte[] someBytes = new byte[1758];
final ThreadPoolExecutor tp = (ThreadPoolExecutor) Executors.newCachedThreadPool();
final AtomicLong clientId = new AtomicLong();
final ConcurrentLinkedQueue<Closeable> closeables = new ConcurrentLinkedQueue<Closeable>();
final long maxWait = 5_000L;
final CountDownLatch serversReady = new CountDownLatch(clients);
final CountDownLatch clientsDone = new CountDownLatch(clients);
ServerSocket ss;
int port;
#Override public void run() {
try {
ss = useDebugSocket ? new DebugServerSocket() : new ServerSocket();
ss.bind(null);
port = ss.getLocalPort();
tp.execute(new SocketAccept());
for (int i = 0; i < clients; i++) {
ClientSideSocket css = new ClientSideSocket();
closeables.add(css);
tp.execute(css);
}
if (!clientsDone.await(maxWait, TimeUnit.MILLISECONDS)) {
System.out.println("CLIENTS DID NOT FINISH");
} else {
System.out.println("Finished");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
close();
}
}
#Override public void close() {
try { if (ss != null) ss.close(); } catch (Exception ignored) {}
Closeable c = null;
while ((c = closeables.poll()) != null) {
try { c.close(); } catch (Exception ignored) {}
}
tp.shutdownNow();
}
class DebugServerSocket extends ServerSocket {
public DebugServerSocket() throws IOException {
super();
}
#Override public DebugSocket accept() throws IOException {
DebugSocket s = new DebugSocket();
implAccept(s);
return s;
}
}
class SocketAccept implements Runnable {
#Override public void run() {
try {
for (int i = 0; i < clients; i++) {
SeverSideSocket sss = new SeverSideSocket(ss.accept());
closeables.add(sss);
tp.execute(sss);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class SeverSideSocket implements Runnable, Closeable {
Socket s;
public SeverSideSocket(Socket s) {
this.s = s;
}
#Override public void run() {
Long l = -1L;
byte[] received = new byte[someBytes.length];
try {
DataInputStream in = new DataInputStream(s.getInputStream());
DataOutputStream out = new DataOutputStream(s.getOutputStream());
serversReady.countDown();
if (!serversReady.await(maxWait, TimeUnit.MILLISECONDS)) {
System.out.println("CLIENTS DID NOT CONNECT ON TIME TO SERVER");
}
l = in.readLong();
in.readFully(received);
out.writeByte(1);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
// write to console at end to prevent synchronized socket I/O
System.out.println("received long: " + l);
close();
}
}
#Override public void close() {
TestDebugSocket.close(s);
s = null;
}
}
class ClientSideSocket implements Runnable, Closeable {
Socket s;
#SuppressWarnings("resource")
#Override public void run() {
Long l = -1L;
Byte b = -1;
try {
s = useDebugSocket ? new DebugSocket() : new Socket();
s.connect(new InetSocketAddress(port));
DataInputStream in = new DataInputStream(s.getInputStream());
DataOutputStream out = new DataOutputStream(s.getOutputStream());
l = clientId.incrementAndGet();
out.writeLong(l);
out.write(someBytes);
out.flush();
b = in.readByte();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("long send: " + l + ", result: " + b);
close();
clientsDone.countDown();
}
}
#Override public void close() {
TestDebugSocket.close(s);
s = null;
}
}
static void close(Socket s) {
try { if (s != null) s.close(); } catch (Exception ignored) {}
}
}
I would like to test the connection between a client and a server in a ScheduledExecutorService every x ms while processing received data from the distant host.
So I did something like this:
public class MyClass {
private final ScheduledExecutorService _timer = Executors.newScheduledThreadPool(1);
private Socket _connection;
public void connectToDistantHost() {
try {
_connection = new Socket();
_connection.connect(_adresseServeur);
new Thread(new Runnable() {
#Override
public void run() {
try {
//let another object know the connection is ok
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
_timer.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
testConnection();
}
}, 0, 200, TimeUnit.MILLISECONDS);
}
private void testConnection() {
//would like to peek on the socket's inputstream to know if something's wrong
}
private void myProcessing() {
while (true) {
...
//read what's inside stream
//process it in a thread
}
}
}
So, if I .read() on the Socket's inputstream it'll screw myProcessing(). I thought about wraping the inputstream in a BufferedReader and mark the buffer position before I read and then reset the position, but as the testing and the processing are in two differents thread it won't work anyway.
How can I do that? Knowing that I did it in c# without much problem:
class TraitementEnvoiClient {
...
private void testConnection(Object obj, ElapsedEventArgs args) {
_connectionIsOk = _connexionAuServeur.IsConnected();
if (!_connectionIsOk) {
tryToReconnect();
}
}
}
public static class ExtensionTcpClient {
//Credit to ElFenix: http://social.msdn.microsoft.com/Forums/en-US/c857cad5-2eb6-4b6c-b0b5-7f4ce320c5cd/c-how-to-determine-if-a-tcpclient-has-been-disconnected?forum=netfxnetcom
public static bool IsConnected(this TcpClient client) {
// Detect if client disconnected
try {
if (client.Client.Poll(0, SelectMode.SelectRead)) {
byte[] buff = new byte[1];
if (client.Client.Receive(buff, SocketFlags.Peek) == 0) {
// Client disconnected
return false;
}
}
} catch (SocketException se) {
return false;
}
return true;
}
}
Thank you
Edit: I would like to make something like that:
private static boolean isConnected(Socket client) {
try {
InputStream is = client.getInputStream();
if(is.peek() == -1) return false;
OutputStream os = client.getOutputStream();
os.write(new byte[]{}); //if it fails a IOException will trigger
} catch(SocketException se) {
return false;
} catch(IOException ioe) {
return false;
}
return true;
}
The testing is redundant. The read or write operations will return -1 if the other end closes or disconnects before or during the operation. There is no point in "testing" the connection first because it may subsequently fail during your IO operation.
See also the other answer mentioned in the comments.
When reading from a socket using a BufferedReader it states that the readLine() method 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
How does it know that it's reached the end of the stream? What sequence of characters does it use to determine this.
I want to simulate sending the same sequence of characters to properly close another connection that uses PipedStreams.
Edit:
Here is the code in question. From the responses it looks like there is no such sequence and calling close() on the PipedOutput stream should unblock the readLine() on the output stream. It doesn't appear to be doing this at the moment which is why I was confused so I'm thinking it might be a bug somewhere else.
What's happening is the incomingEventIn.close() line appears to be blocking when inputLine = incomingEventIn.readLine() is blocking. If inputLine = incomingEventIn.readLine() isn't being executed on the other thread then incomingEventIn.close() executes fine. Why is this happening?
public class SocketManager {
private Socket socket = null;
private PrintWriter out = null;
private BufferedReader in = null;
private PipedOutputStream incomingEventOutStream = null;
private PrintWriter incomingEventOut = null;
private BufferedReader incomingEventIn = null;
private PipedOutputStream incomingResponsOutStream = null;
private PrintWriter incomingResponseOut = null;
private BufferedReader incomingResponseIn = null;
private ArrayList<AsteriskLiveComsEventListener> listeners = new ArrayList<AsteriskLiveComsEventListener>();
private final ExecutorService eventsDispatcherExecutor;
private String ip;
private int port;
private Object socketLock = new Object();
public SocketManager(String ip, int port) {
this.ip = ip;
this.port = port;
eventsDispatcherExecutor = Executors.newSingleThreadExecutor();
}
public void connect() throws UnableToConnectException, AlreadyConnectedException {
synchronized(socketLock) {
if (socket != null && !socket.isClosed()) {
throw (new AlreadyConnectedException());
}
try {
socket = new Socket(ip, port);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
incomingEventOutStream = new PipedOutputStream();
incomingEventIn = new BufferedReader(new InputStreamReader(new PipedInputStream(incomingEventOutStream)));
incomingEventOut = new PrintWriter(incomingEventOutStream);
incomingResponsOutStream = new PipedOutputStream();
incomingResponseIn = new BufferedReader(new InputStreamReader(new PipedInputStream(incomingResponsOutStream)));
incomingResponseOut = new PrintWriter(incomingResponsOutStream);
} catch (IOException e) {
throw (new UnableToConnectException());
}
new Thread(new IncomingEventThread()).start();
new Thread(new SocketThread()).start();
}
}
public void disconnect() throws NotConnectedException {
disconnect(false);
}
private void disconnect(boolean notRequested) throws NotConnectedException {
synchronized(socketLock) {
if (!isConnected()) {
throw (new NotConnectedException());
}
try {
incomingEventIn.close();
} catch (IOException e2) {}
// IT NEVER GETS TO HERE!
incomingEventOut.close();
try {
incomingResponseIn.close();
} catch (IOException e1) {}
System.out.println("disconnecting");
incomingResponseOut.close();
try {
socket.shutdownInput();
} catch (IOException e) {}
try {
socket.shutdownOutput();
} catch (IOException e) {}
try {
socket.close();
} catch (IOException e) {}
if (notRequested) {
System.out.println("disconnecting event");
dispatchEvent(new ConnectionLostEvent());
}
}
}
public boolean isConnected() {
synchronized(socketLock) {
return (socket != null && !socket.isClosed());
}
}
public void addEventListener(AsteriskLiveComsEventListener a) {
synchronized(listeners) {
listeners.add(a);
}
}
public void removeEventListener(AsteriskLiveComsEventListener a) {
synchronized(listeners) {
listeners.remove(a);
}
}
private void dispatchEvent(final AsteriskLiveComsEvent e) {
synchronized (listeners) {
synchronized (eventsDispatcherExecutor) {
eventsDispatcherExecutor.execute(new Runnable()
{
public void run()
{
for(int i=0; i<listeners.size(); i++) {
listeners.get(i).onAsteriskLiveComsEvent(e);
}
}
});
}
}
}
public JSONObject sendRequest(JSONObject request) throws JSONException, NotConnectedException {
synchronized(socketLock) {
System.out.println("sending request "+request.toString());
out.println(request.toString());
try {
return new JSONObject(incomingResponseIn.readLine());
} catch (IOException e) {
// lets close the connection
try {
disconnect(true);
} catch (NotConnectedException e1) {}
throw(new NotConnectedException());
}
}
}
private class SocketThread implements Runnable {
#Override
public void run() {
String inputLine = null;
try {
while((inputLine = in.readLine()) != null) {
// determine if this is a response or event and send to necessary location
JSONObject lineJSON = new JSONObject(inputLine);
if (lineJSON.getString("type").equals("response")) {
incomingResponseOut.println(inputLine);
incomingResponseOut.flush();
}
else if (lineJSON.getString("type").equals("event")) {
incomingEventOut.println(inputLine);
incomingEventOut.flush();
}
}
if (isConnected()) {
try {
disconnect(true);
} catch (NotConnectedException e) {}
}
} catch (IOException e) {
// try and disconnect (if not already disconnected) and end thread
if (isConnected()) {
try {
disconnect(true);
} catch (NotConnectedException e1) {}
}
}
}
}
private class IncomingEventThread implements Runnable {
#Override
public void run() {
String inputLine = null;
try {
while((inputLine = incomingEventIn.readLine()) != null) {
JSONObject lineJSON = new JSONObject(inputLine);
String eventType = lineJSON.getString("eventType");
// determine what type of event it is and then fire one that represents it
if (eventType.equals("channelAdded")) {
JSONObject a = lineJSON.getJSONObject("payload");
Hashtable<String,Object> data = new Hashtable<String,Object>();
Object[] keys = a.keySet().toArray();
for(int i=0; i<keys.length; i++) {
data.put((String) keys[i], a.get((String) keys[i]));
}
dispatchEvent(new ChannelAddedEvent(data));
}
else if (eventType.equals("channelRemoved")) {
dispatchEvent(new ChannelRemovedEvent(lineJSON.getJSONObject("payload").getInt("channelId")));
}
else if (eventType.equals("channelsToRoom")) {
ArrayList<Integer> data = new ArrayList<Integer>();
JSONObject a = lineJSON.getJSONObject("payload");
JSONArray ids = a.getJSONArray("channelIds");
for(int i=0; i<ids.length(); i++) {
data.add(ids.getInt(i));
}
dispatchEvent(new ChannelsToRoomEvent(data));
}
else if (eventType.equals("channelToHolding")) {
dispatchEvent(new ChannelToHoldingEvent(lineJSON.getJSONObject("payload").getInt("channelId")));
}
else if (eventType.equals("channelVerified")) {
dispatchEvent(new ChannelVerifiedEvent(lineJSON.getJSONObject("payload").getInt("channelId")));
}
else if (eventType.equals("serverResetting")) {
dispatchEvent(new ServerResettingEvent());
}
}
} catch (IOException e) {}
System.out.println("here");
}
}
Edit 2:
I think it's a deadlock issue somewhere because if I put some breakpoints in before it in the debugger it runs fine and inputLine = incomingEventIn.readLine() returns null. If I try and run it normally it locks up.
Edit 3: Solved thanks to Gray's answer. The input stream is being closed before the output which was causing the lock up. It needs to be the other way around. Closing the output stream first then informs the input stream that the stream is closed and unblocks the readLine() method.
How does it know that it's reached the end of the stream? What sequence of characters does it use to determine this.
The answer to this is OS dependent but the OS' I'm familiar with, no EOF characters are read. The OS returns to the underlying caller the return values that indicate that the stream (file-descriptor) has reached EOF. The JVM sees the return value and returns the appropriate return (null, -1, ...) to the InputStream or Reader caller depending on the method.
I want to simulate sending the same sequence of characters to properly close another connection that uses PipedStreams.
If you are reading from a PipedReader then you close the associated PipedWriter. The Reader or InputStream will then return the appropriate EOF value to the caller.
Edit:
Since your IncomingEventThread is reading from incomingEventIn, the disconnect() method should close the incomingEventOut first. The thread should close the in side itself. Then you should close the response out.
I would not have the thread call disconnect(...). It should only close it's reader and writer, not all of the streams.
Check out this question:
what is character for end of file of filestream?
There isn't one. The OS knows when the stream reaches its end via the file size, the TCP FIN bit, or other out-of-band mechanisms depending on the source. The only exception I'm aware of is that the terminal driver recognizes Ctrl/d or Ctrl/z as EOF when types by a keyboard, but again that's the OS, not the Java stream or reader.
From your point of view, just call close on PipedOutputStream that you use to connect to your test.
The actual close of the socket is performed by the TCP stack on client and server.
This should do (note that you cannot read/write piped streams on the same thread, hence the 2 methods and a thread creation):
void runTest ( final PipedInputStream sink ) throws Exception
{
try( final PipedOutputStream stream = new PipedOutputStream( sink ) )
{
try ( final OutputStreamWriter swriter =
new OutputStreamWriter( stream, "UTF-8" )
)
{
try ( final PrintWriter writer = new PrintWriter( swriter ) )
{
writer.println( "Hello" );
writer.println( "World!" );
}
}
}
}
void test ( final PipedInputStream sink ) throws InterruptedException
{
final Thread outputThread =
new Thread(
new Runnable ( )
{
#Override
public void run ( )
{
try
{
runTest( sink );
}
catch ( final Exception ex )
{
throw new RuntimeException( ex );
}
}
}
);
outputThread.start( );
outputThread.join( );
}
Consider the following test code.
I am trying to find out if I can use piped streams like "normal" I/O streams, together with the commonly used Reader and Writer implementations (specifically, another part of the code base I am working on demands that I use OutputStreamWriter).
The problem here is that nothing appears to show up on the read end. The program at least appears to correctly write the message to the write-end of the pipe, but when trying to read from the other end I block indefinetly, or if I (as in this case) check for available bytes, the call returns 0.
What am I doing wrong?
public class PipeTest {
private InputStream input;
private OutputStream output;
public PipeTest() throws IOException {
input = new PipedInputStream();
output = new PipedOutputStream((PipedInputStream)input);
}
public void start() {
Stuff1 stuff1 = new Stuff1(input);
Stuff2 stuff2 = new Stuff2(output);
Thread thread = new Thread(stuff1);
thread.start();
Thread thread2 = new Thread(stuff2);
thread2.start();
}
public static void main(String[] args) throws IOException {
new PipeTest().start();
}
private static class Stuff1 implements Runnable {
InputStream inputStream;
public Stuff1(InputStream inputStream) {
this.inputStream = inputStream;
}
#Override
public void run() {
String message;
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
//message = reader.readLine();
System.out.println("Got message!");
System.out.println(inputStream.available());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private static class Stuff2 implements Runnable {
OutputStream outputStream;
public Stuff2(OutputStream outputStream) {
this.outputStream = outputStream;
}
#Override
public void run() {
String message = "Hej!!\n";
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
try {
writer.write(message);
System.out.println("Wrote message!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
As you are never reading from the read end, it is impossible to see how you could possibly arrive at that conclusion, and any such conclusion is therefore baseless and invalid.
All you are doing is printing available() at an arbitrary point in time, which isn't sufficient to prove that nothing ever shows up at the read end.