Peek on a socket InputStream - java

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.

Related

Android Java: Proxy-App without Port-Forwarding

I have to create a simple rotating proxy application where 100 requests get evenly distributed to 10 devices. I've got the following structure:
WebServer with a Java-SocketServer running. All Android devices are connected to this Socket-Server to be able to know which devices are currently online and for determining which device should be used for the next request.
10 Android devices in different networks. They are connected to the Socket Server and are waiting for requests that should be forwarded to the remote address and then sent back to the SocketServer.
In easy words: I basically have to create an application similar like Honeygain, Peer2Profit or IPRoyal Pawns so that I can later do requests like this:
//Use "-x" to set Proxy-IP and Proxy-Port
curl -x ANDROID_DEVICE_IP:PORT -L https://www.google.com
I managed to have an always running proxy service in an Android application. It basically looks like this and just forwards HTTP-Requests from Port 1440 to the desired remote address and then sends the response back to the original client. The Proxy basically works fine.
public class ProxyServerThread extends Thread {
public static void main(String[] args) {
(new ProxyServerThread()).run();
}
public ProxyServerThread() {
super("Server Thread");
}
#Override
public void run() {
try (ServerSocket serverSocket = new ServerSocket(1440)) {
Socket socket;
try {
while ((socket = serverSocket.accept()) != null) {
(new Handler(socket)).start();
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
return;
}
}
public static class Handler extends Thread {
public static final Pattern CONNECT_PATTERN = Pattern.compile("CONNECT (.+):(.+) HTTP/(1\\.[01])", Pattern.CASE_INSENSITIVE);
private final Socket clientSocket;
private boolean previousWasR = false;
public Handler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
try {
String request = readLine(clientSocket);
System.out.println(request);
Matcher matcher = CONNECT_PATTERN.matcher(request);
if (matcher.matches()) {
String header;
do {
header = readLine(clientSocket);
} while (!"".equals(header));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(clientSocket.getOutputStream(), "ISO-8859-1");
final Socket forwardSocket;
try {
forwardSocket = new Socket(matcher.group(1), Integer.parseInt(matcher.group(2)));
System.out.println(forwardSocket);
} catch (IOException | NumberFormatException e) {
e.printStackTrace(); // TODO: implement catch
outputStreamWriter.write("HTTP/" + matcher.group(3) + " 502 Bad Gateway\r\n");
outputStreamWriter.write("Proxy-agent: Simple/0.1\r\n");
outputStreamWriter.write("\r\n");
outputStreamWriter.flush();
return;
}
try {
outputStreamWriter.write("HTTP/" + matcher.group(3) + " 200 Connection established\r\n");
outputStreamWriter.write("Proxy-agent: Simple/0.1\r\n");
outputStreamWriter.write("\r\n");
outputStreamWriter.flush();
Thread remoteToClient = new Thread() {
#Override
public void run() {
forwardData(forwardSocket, clientSocket);
}
};
remoteToClient.start();
try {
if (previousWasR) {
int read = clientSocket.getInputStream().read();
if (read != -1) {
if (read != '\n') {
forwardSocket.getOutputStream().write(read);
}
forwardData(clientSocket, forwardSocket);
} else {
if (!forwardSocket.isOutputShutdown()) {
forwardSocket.shutdownOutput();
}
if (!clientSocket.isInputShutdown()) {
clientSocket.shutdownInput();
}
}
} else {
forwardData(clientSocket, forwardSocket);
}
} finally {
try {
remoteToClient.join();
} catch (InterruptedException e) {
e.printStackTrace(); // TODO: implement catch
}
}
} finally {
forwardSocket.close();
}
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
}
}
}
private static void forwardData(Socket inputSocket, Socket outputSocket) {
try {
InputStream inputStream = inputSocket.getInputStream();
try {
OutputStream outputStream = outputSocket.getOutputStream();
try {
byte[] buffer = new byte[4096];
int read;
do {
read = inputStream.read(buffer);
if (read > 0) {
outputStream.write(buffer, 0, read);
if (inputStream.available() < 1) {
outputStream.flush();
}
}
} while (read >= 0);
} finally {
if (!outputSocket.isOutputShutdown()) {
outputSocket.shutdownOutput();
}
}
} finally {
if (!inputSocket.isInputShutdown()) {
inputSocket.shutdownInput();
}
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
}
}
private String readLine(Socket socket) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int next;
readerLoop:
while ((next = socket.getInputStream().read()) != -1) {
if (previousWasR && next == '\n') {
previousWasR = false;
continue;
}
previousWasR = false;
switch (next) {
case '\r':
previousWasR = true;
break readerLoop;
case '\n':
break readerLoop;
default:
byteArrayOutputStream.write(next);
break;
}
}
return byteArrayOutputStream.toString("ISO-8859-1");
}
}
}
Here comes the Problem:
Everything works fine but only on the local network. I cannot manage to get this to work without port forwarding. Since all devices are on their mobile cellular data I need a way to be able to connect to the device anyway.
How do the mentioned apps manage to connect to the devices?

Asynchronous read from COM port (using JSSC lib)

My project used JSSC library for linking PC and microcontroller.
Write method:
public void write(byte[] buffer) throws SerialPortException {
if (serialPort.isOpened())
serialPort.writeBytes(buffer);
}
Read method:
public byte[] read() throws SerialPortException {
byte[] result = null;
FutureTask<byte[]> task = new FutureTask<>(new PortReader());
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
result = (byte[]) executor.submit(task).get(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
System.err.println(getClass().getSimpleName() + " READ: Timeout exception!");
}
return result;
}
private class PortReader implements Callable<byte[]>, SerialPortEventListener {
private byte[] data = null;
#Override
public void serialEvent(SerialPortEvent event) {
if (event.isRXCHAR() && event.getEventValue() > 0) {
try {
data = serialPort.readBytes(event.getEventValue());
} catch (SerialPortException e) {
e.printStackTrace();
}
}
}
#Override
public byte[] call() throws Exception {
if (data == null)
Thread.sleep(200);
return data;
}
}
I tried to implement a synchronous write (immediately send data) to the port and asynchronous read (waiting for the input data at least 1000 ms) from port.
Is it correct decision? Maybe there are other ways of asynchronous data reading?
Thank you!
Better to use the wait event as used inside serialport class. This way makes the port to wait until a command is equecuted.
serialPort.writeBytes(buffer);//Write data to port
serialPort.addEventListener(new PortReader(serialPort), SerialPort.MASK_RXCHAR);
int[][] eventArray=serialPort.waitEvents()
for (int i = 0; i < eventArray.length; i++) {
if ((eventArray[i][0] > 0) ) {
serialPort.eventListener.serialEvent(new SerialPortEvent("COM1", eventArray[i][0], eventArray[i][1])); //give your port name and the events got.
}
}

ObjectInputStream consumes too much memory

I have a Socket that sends a list of Objects every few seconds to a client through ObjectOutputStream. On the server side, after every writeObject(myList) i execute flush then reset. Using VisualVM to check for memory usage, on the server there's no memory leaks, but on the client it seems that the previously read Lists are kept in memory. I tried to execute reset on the ObjectInputStream on the client side but looks like ObjectInputStream does not support this method (it throws a java.io.IOException: mark/reset not supported).
This is my server socket:
public class ConsultaBombas {
public static void inicializarServidorSocket() {
try {
ServerSocket serverSocket = new ServerSocket(5963);
Thread thread = new Thread(() -> {
while (!serverSocket.isClosed()) {
try {
final Socket socket = serverSocket.accept();
new ThreadComunicacao(socket).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.setName("Consulta bombas (Inicializador)");
thread.start();
} catch (Exception e) {
e.printStackTrace();
}
}
static class ThreadComunicacao extends Thread {
private Socket socket;
public ThreadComunicacao(Socket socket) {
this.socket = socket;
setName("Consulta bombas (Comunicação) com início: " + new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date()));
}
#Override
public void run() {
try {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
while (!socket.isClosed()) {
List<Bomba> bombas = new DaoBomba().findAll();
out.writeObject(bombas);
out.flush();
out.reset();
Thread.sleep(1000);
}
} catch (SocketException e) {
if (e.getLocalizedMessage() != null && e.getLocalizedMessage().equalsIgnoreCase("Connection reset by peer: socket write error")) {
System.out.println("Cliente desconectou...");
} else {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
An this is the client (started with start() method):
public class ConsultaBombasClient {
private Socket socket;
private Thread threadConsulta;
public ConsultaBombasClient(BombasListener bombasListener, String maquinaDestino) {
threadConsulta = new Thread(() -> {
try {
Thread.currentThread().setName("Consulta Bombas");
System.out.println("Endereço bagual: "+maquinaDestino);
socket = new Socket(maquinaDestino, 5963);
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Object leitura;
while ((leitura = in.readObject()) != null) {
List<Bomba> bombas = (List<Bomba>) leitura;
bombasListener.run(bombas);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
});
threadConsulta.setDaemon(true);
}
public void start() {
threadConsulta.start();
}
public interface BombasListener {
void run(List<Bomba> bombas);
}
}
What am i doing wrong?
garbage collection is not immediate, do you have any real memory troubles? Have you tried running the client with low -Xmx value, did you receive the OutOfMemoryError?
– user3707125
You're right, after some time when the memory gets close to the maximum heap size, it clears the objects from memory. I wasn't seeing this because i have a lot of RAM in my pc but with Xmx50m i could see this working as you said. – Mateus Viccari
Clearly bombasListener.run(), whatever it may be, is not releasing the supplied list.
NB ObjectInputStream.readObject() does not return null at end of stream. It is therefore incorrect to use this test as a termination condition for a read loop.

java rxtx SerialWriter issue

I am using RXTX to communicate between JAVA and a microcontroller.
This is the JAVA code for opening a connection, sending and receiving data
package app;
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class SerialCommunication1 {
private static SerialCommunication1 instance = null;
private static boolean coonected = false;
public static SerialCommunication1 getInstance(){
if(instance == null)
instance = new SerialCommunication1();
return instance;
}
private SerialCommunication1() {
super();
try {
connect("COM4");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SerialCommunication1.coonected = true;
}
void connect(String portName) throws Exception {
CommPortIdentifier portIdentifier = CommPortIdentifier
.getPortIdentifier(portName);
if (portIdentifier.isCurrentlyOwned()) {
System.out.println("Error: Port is currently in use");
} else {
CommPort commPort = portIdentifier.open(this.getClass().getName(),
2000);
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,
SerialPort.STOPBITS_2, SerialPort.PARITY_NONE);
InputStream in = serialPort.getInputStream();
OutputStream out = serialPort.getOutputStream();
(new Thread(new SerialReader(in))).start();
(new Thread(new SerialWriter(out))).start();
} else {
System.out
.println("Error: Only serial ports are handled by this example.");
}
}
}
/** */
public static class SerialReader implements Runnable {
InputStream in;
public SerialReader(InputStream in) {
this.in = in;
}
public void run() {
byte[] buffer = new byte[1024];
int len = -1;
try {
while ((len = this.in.read(buffer)) > -1) {
System.out.print(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/** */
public static class SerialWriter implements Runnable {
OutputStream out;
static String str = null;
public SerialWriter(OutputStream out) {
this.out = out;
}
public void run() {
System.out.println("Will try to execute");
try {
if(str.length() > 0){
this.out.write(str.getBytes());
str = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
And this is the Java code that is calling when an event triggers
SerialCommunication1.getInstance();
if(ledStatus == true) {SerialCommunication1.SerialWriter.str = "4A01";}
else {SerialCommunication1.SerialWriter.str = "4A00";}
stopProcess();
And now the problem. I need to send a command to my microcontroller with the code 4A01 and, after receiving the answer, I need to call it again with the code 4A00. The calls are triggered by a button from my Java interface. The problem is that the second call is not executed (4A00 is not sending). I tried to inverse the command codes and they work well. After the first one (4A01) is executed, my microcontroller reacts and sends the response which is read by java and my interface is updated. When I send the invers command (4A00) it stops exactly at this line SerialCommunication1.SerialWriter.str = "4A00"; and doesn't even enter inside the SerialWriter's run() method.
Do you have any idea why is this happening? From the side of my microcontroller there is no problem, I checked all the possibilities with a tool.
I hope I made myself clear.
Thank you!
LE: I forgot to tel you that it didn't throw any errors or exceptions
I'm not sure because I'm not able to test your code but I think your problem is in SerialWriter class:
public static class SerialWriter implements Runnable {
OutputStream out;
static String str = null; // Here str is initialized to null
public SerialWriter(OutputStream out) {
this.out = out;
}
public void run() {
System.out.println("Will try to execute");
try {
if(str.length() > 0) { // this should throw NPE because str is null
this.out.write(str.getBytes());
str = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Since there is no loop in this method, then the thread created within SerialCommunication1 at this line:
(new Thread(new SerialWriter(out))).start();
most likely finishes its execution after sending the first str.
Honestly I don't understand how does it even send a single string, since str is initialized to null in first place and it should throw NullPointerException at str.length() line.
I would suggest you this approach:
Don't trigger a writer thread when connection is established, just trigger a new one every time a message will be sent.
Use Singleton pattern correctly.
Keep a reference to the serial port in SerialCommunication1 class.
Translated to code it would be something like this:
class SerialWriter implements Runnable {
OutputStream out;
String message;
public SerialWriter(OutputStream out) {
this.out = out;
}
public void setMessage(String msg) {
this.message = msg;
}
public void run() {
try {
if(message != null) {
this.out.write(str.getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then in SerialCommunication1 class add this public method:
public void sendMessage(String msg) {
SerialWriter writer = new SerialWriter(serialPort.getOutputStream()); // of course you'll have to keep reference to serialPort when connection is established
writer.setMessage(msg);
(new Thread(writer)).start();
}
And finally call this method in this way:
SerialCommunication1.getInstance().sendMessage("4A01");
tzortzik,
I think tha is a timeout problem. Try to addding a delay to writer :
/** */
public static class SerialWriter implements Runnable {
OutputStream out;
static String str = null;
public SerialWriter(OutputStream out) {
this.out = out;
}
public void run() {
Thread.sleep(500); //<----------- this should be in mainThread before to SerialWriter.start();
System.out.println("Will try to execute");
try {
if(str.length() > 0){
this.out.write(str.getBytes());
str = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
It happens to me many times, "we should learn to wait for a response" (^_^)
Check if you are executing well a secuence like the next:
Send command 4A01
Receive response 4A01 from micro
WAIT FOR RESPONSE BEFORE SEND SECOND COMMAND. Thread.sleep(500); //wait for 500 milis or more
Send command 4A00
Receive response 4A00 from micro
I hope it could help you.

What character does a BufferedReader interpret as the end of the stream?

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( );
}

Categories

Resources