"Endless" AudioInputStream from socket - java

I have a problem with creation of AudioInputStream from Socket.
Here are the important parts:
public class SoundStream extends Thread {
private int port;
private String IP;
private Socket socket;
private SoundObject soundObject;
private OpenAL openAL;
private Source source;
private boolean run = true;
public SoundStream(int port, String IP, SoundObject soundObject) {
this.soundObject = soundObject;
this.port = port;
this.IP = IP;
}
public void run() {
try {
this.socket = new Socket(this.IP, this.port);
this.openAL = new OpenAL();
} catch (Exception e) {
e.printStackTrace();
}
this.mainCycleMethod();
}
private void mainCycleMethod() {
while (run) {
this.soundObject.blockAndWait();
switch (this.soundObject.getAndResetEvent()) {
case 0:
this.run = false;
this.close();
break;
case 1:
this.setPitch();
break;
case 2:
this.closeSource();
this.play();
break;
case 3:
this.pause(true);
break;
case 4:
this.pause(false);
break;
}
}
}
private BufferedInputStream getInputStream() throws Exception {
return new BufferedInputStream(socket.getInputStream());
}
private void setPitch() {
if(this.source != null) {
try {
this.source.setPitch(this.soundObject.getPitch());
} catch (ALException e) {
e.printStackTrace();
}
}
}
private void play() {
try {
AudioInputStream audioInputStream = new AudioInputStream(this.getInputStream(), this.soundObject.getAudioFormat(), AudioSystem.NOT_SPECIFIED);
// AudioInputStream audioInputStream_tmp = AudioSystem.getAudioInputStream(this.getInputStream());
// AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(this.soundObject.getAudioFormat(), audioInputStream_tmp);
this.source = openAL.createSource(audioInputStream);
this.source.setGain(1f);
this.source.play();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void close() {
this.closeSource();
this.openAL.close();
try {
this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void closeSource() {
if(this.source!=null) {
this.source.close();
}
}
private void pause(boolean pause) {
if(this.source != null) {
try {
if (pause) {
this.source.pause();
} else {
this.source.play();
}
} catch (ALException ex) {
ex.printStackTrace();
}
}
}
}
public class SoundObject extends AbstractEventObject {
public AudioFormat getAudioFormat() {
boolean signed = false;
//true,false
boolean bigEndian = false;
//true,false
return new AudioFormat(this.frequency, this.bits, this.channels, signed, bigEndian);
}
.
.
.
.
}
This code throws UnsupportedAudioFileException at this line:
AudioInputStream audioInputStream_tmp = AudioSystem.getAudioInputStream(this.getInputStream());
However when I use this code:
AudioInputStream audioInputStream = new AudioInputStream(this.getInputStream(), this.soundObject.getAudioFormat(), 100000);
it plays the sound but only after it loads those 100000 sample frames to the audioinputstream. After it plays all the 100000 frames it finishes.
I guess that I would solve this issue if I could pass the AudioFormat directly as a parameter during the first AudioInputStream inicialization, but it doesn't seem to be possible.
I'm receiving the audio format specifications from server.
I think that one possible solution would be to create a dataline which I can pass as a parametr to AudioInputStream constructor. However I'm not sure how to get the data from the socket directly to dataline. I know of a solution that uses infinite loop, in which it reads the data and writes them to the dataline. But it seems to be wasteful. Is there a more direct approach?
I hope it's possible to solve using java-openAL library, because I need to change the speed and I hope I won't have to do it myself.
Thanks

I've finally solved the issue. As it turned out java-openAL has streaming support built in, but it wasn't in the documentation on GitHub so I didn't notice at first. There is a createOutputStream method in the Source class, which returns the OutputStream. You can write the bytes directly to the OutputStream.
Here is my code:
In this snippet I initialize OpenAL:
public void run() {
try {
this.socket = new Socket(this.IP, this.port);
this.openAL = new OpenAL();
} catch (Exception ex) {
Log.severe(ex.toString());
}
this.mainCycleMethod();
}
Here is my play method which is called when the InputStream is available:
private void play() {
try {
this.source = openAL.createSource();
this.outputWriter = new OutputWriter(this.socket.getInputStream(), this.source, this.soundObject.getAudioFormat());
this.source.setGain(1f);
this.outputWriter.start();
} catch (Exception ex) {
Log.severe(ex.toString());
}
}
You have to use createSource method without parameters, it returns new instance of Source. Don't call the play method on source, it's handled by the SourceOutputStream class which instance is returned by the createOutputStream method. There is nothing wrong with calling the play method manually but I had a bad experience doing so when the buffers are empty. Basically it doesn't start playing later on when you begin streaming the data to OpenAL.
Here is my OutputWriter code which takes care of passing the bytes from InputStream to OutputStream:
package cz.speechtech.sound;
import org.urish.openal.ALException;
import org.urish.openal.Source;
import javax.sound.sampled.AudioFormat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Created by honza on 16.12.15.
*/
public class OutputWriter extends Thread {
private InputStream inputStream;
private OutputStream outputStream;
private int STREAMING_BUFFER_SIZE = 24000;
private int NUMBER_OF_BUFFERS = 4;
private boolean run = true;
public OutputWriter(InputStream inputStream, Source source, AudioFormat audioFormat) {
this.inputStream = inputStream;
try {
this.outputStream = source.createOutputStream(audioFormat, this.NUMBER_OF_BUFFERS, 1024);
} catch (ALException e) {
e.printStackTrace();
}
}
public void run() {
byte[] buffer = new byte[this.STREAMING_BUFFER_SIZE];
int i;
try {
Thread.sleep(1000); // Might cause problems
while (this.run) {
i = this.inputStream.read(buffer);
if (i == -1) break;
outputStream.write(buffer, 0, i);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void stopRunning() {
this.run = false;
try {
this.outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Have a nice day.

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?

Java Socket InputStream read missing bytes

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) {}
}
}

Peek on a socket InputStream

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.

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.

Program won't continue after initializing input/output streams?

Before people suspect that I have no idea what I'm doing at all (and end up voting this down for no reason at all), please read this:
It connects to my server just fine! I'm getting no errors (from the client OR server), and my server is recognizing the connection. It works with my friend's client that he made, but I wanted to make my own client, and apparently I'm doing something wrong. PLEASE STAY ON TOPIC! Thanks :)
Title basically says it all. I've tested with println messages above and below the setupStream() in my Client.java run(), but only the message above the setupStream() prints. I'm not sure how I'm supposed to initialize my stream without making my program come to a halt.
Client.java
import java.io.IOException;
public class Client extends Stream implements Runnable {
public boolean running = false;
private Thread clientThread;
Frame frame;
public Client() {
super("localhost", 43594);
frame = new ClientFrame(500, 500);
start();
}
public synchronized void start() {
if(running) return;
running = true;
clientThread = new Thread(this);
clientThread.start();
}
public synchronized void stop() {
if(!running) return;
running = false;
clientThread.interrupt();
try {
clientThread.join();
} catch (InterruptedException e) {e.printStackTrace();}
}
public void run() {
try{
setupStream();
while(running) {
System.out.println("running");
}
}catch(IOException e) {
e.printStackTrace();
}finally {
try{
out.close();
in.close();
socket.close();
clientThread.join();
}catch(IOException | InterruptedException e) { e.printStackTrace(); }
}
}
public static void main(String[] args) {
new Client();
}
}
Stream.java
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class Stream {
Socket socket;
ObjectOutputStream out;
ObjectInputStream in;
String data;
public Stream(String host, int port) {
try {
socket = new Socket(host, port);
} catch (IOException e) {
e.printStackTrace();
}
}
protected void setupStream() throws IOException {
out = new ObjectOutputStream(socket.getOutputStream());
out.flush();
in = new ObjectInputStream(socket.getInputStream());
}
}
My Server Thread:
package Server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
public class User extends Thread {
public static int users = 0;
public int ID;
public String username;
boolean online = false;
public static ArrayList<String> usernames = new ArrayList<String>();
Socket socket;
DataOutputStream out;
DataInputStream in;
String input;
public User(Socket socket) {
this.socket = socket;
}
public String decode(String input) {
String[] split = input.split(" ");
if(input.startsWith("::")) {
try {
switch(split[0].substring(2, split[0].length()).toLowerCase()) {
case "setname":
case "changename":
case "newname":
if(usernames.contains(split[1].toLowerCase())) {
out.writeUTF("This name is already taken! Please choose a different one.");
out.flush();
return null;
}
if(username == null) {
username = split[1].substring(0, 1).toUpperCase() + split[1].substring(1, split[1].length());
Server.users.put(split[1].toLowerCase(), Server.user[ID]);
usernames.add(split[1].toLowerCase());
} else {
usernames.remove(username.toLowerCase());
username = split[1].substring(0, 1).toUpperCase() + split[1].substring(1, split[1].length());
usernames.add(split[1].toLowerCase());
}
return null;
case "rank+":
return null;
case "[sm]=":
return null;
}
}catch(IOException e) { }
}
return input;
}
String timeStamp;
public void run() {
try {
out = new DataOutputStream(socket.getOutputStream());
out.flush();
in = new DataInputStream(socket.getInputStream());
while((input = in.readUTF()) != null) {
input = decode(input);
if(input != null) {
if(username != null) {
timeStamp = new SimpleDateFormat("[h:mm:ss] ").format(Calendar.getInstance().getTime());
Server.sendGlobalMessage(timeStamp + username +": "+input);
} else {
timeStamp = new SimpleDateFormat("[h:mm:ss] ").format(Calendar.getInstance().getTime());
Server.sendGlobalMessage(timeStamp + "Guest "+ID+": "+input);
}
}
}
}catch(IOException e) { e.printStackTrace(); } finally {
try{
out.close();
in.close();
socket.close();
} catch(IOException e) { e.printStackTrace(); }
}
}
}
I haven't touched the code of my Server Thread for a while, since it has always worked up until I made my new client.
I suspect that your server does not create an ObjectOutputStream, so when the client constructs its ObjectInputStream, it blocks waiting for the object stream header, which never arrives.

Categories

Resources