Java inputStream to String Hangs - java

I am developing a tool to get client information, send to a server, and receive the information again (a proxy). I'm also trying to dump the data being received from the server. I can read the Integer representation of the inputStream, but I am not able to read the String format. I've tried the below example, but it hangs and never connects to the server. Also, System.out.println(inputStream.nextLine()) displays only one line and hangs.
public void run() {
try {
int i;
while ((i = inputStream.read()) != -1){
System.out.println(IOUtils.toString(inputStream));
outputStream.write(i);
}
} catch (IOException e) {
System.out.println("Lost connection to the client.");
}
}

My guess at this is that you're reading from the input stream, and then using the IOUtils library to read from the stream too. My suspicion is that your application is reading the first byte from the input stream, then reading the remainder of the inputstream with the IOUtils library, and then printing out the initial byte that was read.
It doesn't make any sense to call IOUtils.toString(inputstream) from within a loop. That method call will put all the data from the inputstream into a string. Why have the loop at all in this case?
You might want to try not using the IOUtils library for this. Just read a byte of data, push it into a StringBuilder, and then print that byte. In this approach, the loop would be necessary, and you'll probably get what you're looking for.
Try something like this, but modify it as necessary to print the data at the same time to your output stream:
public static String inputStreamToString(final InputStream is, final int bufferSize)
{
final char[] buffer = new char[bufferSize];
final StringBuilder out = new StringBuilder();
try {
final Reader in = new InputStreamReader(is, "UTF-8");
try {
for (;;) {
int rsz = in.read(buffer, 0, buffer.length);
if (rsz < 0)
break;
out.append(buffer, 0, rsz);
}
}
finally {
in.close();
}
}
catch (UnsupportedEncodingException ex) {
/* ... */
}
catch (IOException ex) {
/* ... */
}
return out.toString();
}

The code you posted doesn't attempt to connect to the server, but if any of it executes you must already have connected.
If your program is hanging in this code, either the server hasn't sent any data yet, or the IOUtils.toString() method probably tries to read to EOS, so if the peer doesn't close the connection you will block here forever.
If your program hangs at a readLine() call it means the peer hasn't sent a line to read.

Related

Java Asynchroussocketchannel.read using future problem

I am trying to create an application where my client program reads the message from echo server. I'm trying to use Future to read the message from the server that will have a larger size than my allocated bytebuffer. My thought is to read into a outputstream until end-of-stream. However I think the code will stuck at readBytes = socket.read(buffer).get() at the last try becuase there will be nothing left to read from the socketchannel and Future will be blocked here.
Please let me know how to fix this or another way around.
public String receiveMessage(){
String message = "";
if (socket.isOpen()) {
try {
ByteBuffer buffer = ByteBuffer.allocate(2);
Future<Integer> readResult = socket.read(buffer);
int readBytes = readResult.get();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
while (readBytes != -1) {
outputStream.write(buffer.array());
buffer.clear();
readBytes = socket.read(buffer).get();//stuck at here
}
byte result[] = outputStream.toByteArray();
System.out.println(result);
message = new String(result, Charset.defaultCharset()).trim();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return message;
}
'''
As this is an assignment, I believe I am not supposed to provide a completely functional answer, but here are some hints to guide you:
Oracle has many great Java tutorials including the one on sockets.
For asynchronous execution, I recommend creating a new java.lang.Thread object. Threads and Concurrency (unsurprisingly) also has a tutorial by Oracle. You may have something like the following, which I found useful when experimenting with Java sockets.
// write to server
Socket socket = //...
String message = //...
try (PrintWriter writer = new PrintWriter(socket.getOutputStream(), false)) {
writer.println(message);
// will auto-flush on '\n' (newline character) if 'false' in constructor is changed to
// true or omitted (look at PrintWriter documentation)
writer.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
}
// read from server
Socket socket = //...
try (BufferedReader reader = new BufferedReader(new InputReader(socket.getInputStream()))) {
// TODO
} catch (IOException ioe) {
ioe.printStackTrace();
}
// pipe input stream to output stream
// Perhaps you want what comes from the server to go directly into stdout
Socket socket = //...
new Thread() {
#Override
public void run() {
try {
socket.getInputStream().transferTo(System.out);
// socket input stream is at end of stream, but not necessarily closed
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
Note that using InputStream#transferTo(OutputStream) will not terminate until the InputStream is closed, which is why you might want to execute it in its own thread.
Also, be careful about the above code segment: if you send a message through a socket using a PrintWriter then immediately close the PrintWriter, the PrintWriter will try to close the underlying OutputStream. Once that closes, it will generally try to close the Socket (whose OutputStream was being written to by the PrintWriter), and no more communication can be done through that socket (which will lead to a BrokenPipeException on attempted further use). So, perhaps try to send a message using newline characters as delimiters or something similar, which would be convenient for using a BufferedReader.

How do I prevent a file from corrupting when I transfer it over a local network using sockets?

I am working on a school project where I want to make a personal storage server. At the moment, what I am trying to achieve is being able to transfer a file from the client machine to the server. However, when testing this with an image, the file partially sends before it corrupts.
Please bare in mind that I am a reasonably new programmer and that my technical knowledge may be some-what limited.
I am using a byte array through a DataOutputStream to transfer the file. I want to use this method as it should work for any file type. I've tried to set the buffer size to the exact size of the file and larger but neither have worked.
Server:
public void run() {
try {
System.out.println("ip: " + clientSocket.getInetAddress().getHostAddress());
out = new DataOutputStream(clientSocket.getOutputStream());
in = new DataInputStream(clientSocket.getInputStream());
in.read(buffer, 0, buffer.length);
fileOut = new FileOutputStream("X:\\My Documents\\My
Pictures\\gradient.jpg");
fileOut.write(buffer, 0, buffer.length);
in.close();
out.close();
clientSocket.close();
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
Client:
public void startConnection(String ip, int port) {
try {
clientSocket = new Socket(ip, port);
out = new DataOutputStream(clientSocket.getOutputStream());
in = new DataInputStream(clientSocket.getInputStream());
x = false;
Path filePath = Paths.get("C:\\Users\\georg\\Documents\\gradient.jpg");
buffer = Files.readAllBytes(filePath);
Thread.sleep(3000);
//Files.write(filePath, buffer);
//out.write(buffer,0,buffer.length);
x = true;
sendMessage(buffer);
} catch (IOException ex) {
System.out.println(ex.getMessage());
} catch (InterruptedException ex) {
Logger.getLogger(PCS_Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
public byte[] sendMessage(byte[] buffer) {
if (x==true){
try {
out.write(buffer,0,buffer.length);
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
return null;
}
Here is a comparison of the files I've tried to send vs the files I receive:
https://imgur.com/gallery/T7nUUJT
Curiously, sending a single colour image produces a single colour image on the server. I believe the issue here may have to be in the timing of code execution however I am not sure and do not know how to go about fixing it.
The issue is in your server code, at this line:
in.read(buffer, 0, buffer.length);
You expect to read all the data at once, but if you read the doc you will find this:
public final int read(byte[] b,
int off,
int len)
throws IOException
Reads up to len bytes of data from the contained input stream into an
array of bytes. An attempt is made to read as many as len bytes, but a
smaller number may be read, possibly zero. The number of bytes
actually read is returned as an integer.
The important part is Reads up to len bytes of data.
You must use the return value of read and call it read repeatedly until the is nothing more to read.

Buffered Socket Reader doesn't wait for data from remote connection

I have a Java program that reads data from a TCP source all works fine, except when my program (which acts as a client to the data source) is faster then then the source can respond BufferedReader.ready() throws an exception that closes my TCP connection, as it should. Is there any preferred way/method that I can keep the BufferedReader waiting for new input since my source can sometimes have a slight delay.
Here is the part that i am talking about:
public aDataServer(String host, int port, StreamConnection aConnection) throws UnknownHostException, IOException {
this.aConnection = aConnection;
ndataServerSocket = new Socket(Inet4Address.getByName(host),port);
ndataServerReader = new BufferedReader(new InputStreamReader(ndataServerSocket.getInputStream()));
}
public void run() {
try {
RemoteDevice dev = RemoteDevice.getRemoteDevice(aConnection);
OutputStream outputStream = aConnection.openOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(outputStream);
do {
try {
String ndata = ndataServerReader.readLine();
osw.write(ndata+"\n");
osw.flush();
LOG.log(Level.INFO,"Sent");
} catch(IOException io) {
LOG.log(Level.SEVERE, "Client device({0}) disconnected: \n{1}", new Object[]{dev.getFriendlyName(true), io.getMessage()});
break;
}
}while(ndataServerReader.ready());
} catch (IOException ioe) {
LOG.severe(ioe.getMessage());
} finally {
try {
if (ndataServerSocket != null) {
ndataServerSocket.close();
}
if (ndataServerReader
!= null) {
ndataServerReader.close();
}
} catch (IOException ex) {
LOG.log(Level.SEVERE, ex.getMessage());
}
}
You shouldn't be using ndataServerReader.ready(). Your do/while loop (which should almost certainly just be a while loop) appears to assume that ndataServerReader.ready() indicates there's more data to be read, which is not what it's for.
The Javadoc for Reader describes the ready() method as:
Tells whether this stream is ready to be read.
Returns: True if the next read() is guaranteed not to block for input, false
otherwise. Note that returning false does not guarantee that the next
read will block.
In other worse, Reader.ready() will return false if the reader will wait for more data before returning if you attempt to read from it. This does not mean the Reader is done, and in fact you should expect this method to return false often when working with a network stream, as it could easily have delays.
Your code currently is likely reading one line (in the do block) then checking if the reader is ready (in the while), which it probably isn't, and then exiting successfully. No exceptions are being thrown - you'd see a SEVERE level logging message if they were.
Instead of using ready(), take advantage of the documented behavior of readLine() that says it 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
In other words, simply doing:
String ndata = reader.readLine();
while (ndata != null) {
osw.write(ndata+"\n");
osw.flush();
LOG.log(Level.INFO,"Sent");
ndata reader.readLine();
}
Is sufficient to read the whole input stream.
Reference reading: What's the difference between (reader.ready()) and using a for loop to read through a file?

Why do I get exception error while trying to reset Reader to 0 position?

I'm trying to read a webpage using following code :
URL url = new URL("somewebsitecomeshere");
URLConnection c = url.openConnection();
if(getHttpResponseCode(c) == 200)
{
if (isContentValid(c))//accept html/xml only!
{
InputStream is = c.getInputStream();
Reader r = new InputStreamReader(is);
System.out.println(r.toString());
//after commenting this everything works great!
setHTMLString(getStringFromReader(r));
System.out.println(getHTMLString());
ParserDelegator parser = new ParserDelegator();
parser.parse(r, new Parser(url), true);
r.close();
is.close();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
log("content is not valid!");
}
else
{
System.out.println("ERROR" + c.getContentType() + c.getURL());
}
//---------------------------------------------------
private String getStringFromReader(Reader reader) throws IOException {
char[] arr = new char[8*1024]; // 8K at a time
StringBuffer buf = new StringBuffer();
int numChars;
while ((numChars = reader.read(arr, 0, arr.length)) > 0) {
buf.append(arr, 0, numChars);
}
//Reset position to 0
reader.reset();
return buf.toString();
}
if try to read string using getStringFromReader() the rest of the code will be ignored due to changing position of Reader to EOF so I tried to reset the position to 0 but I got the following error :
java.io.IOException: reset() not supported
at java.io.Reader.reset(Unknown Source)
at sample.getStringFromReader(Spider.java:248)
at default(sample.java:286)
at default.main(sample.java:130)
How can I reset the Reader position to 0?
Short answer, your stream doesn't support reset or mark methods. Check the result of:
is.markSupported()
Long answer, an InputStream is a flow of bytes. Bytes can come from a file, a network resource, a string, etc. So basically, there are streams that don't support resetting the reader position to the start of the stream, while others do (random access file).
A stream from a web site will normally use underlying network connection to provide the data. It means that it's up to the underlying network protocol (TCP/IP for example) to support or not resetting the stream, and normally they don't.
In order to reset any stream you would have to know the entire flow, from start to end. Network communications send a bunch of packages (which may be in order or not) to transfer data. Packages may get lost or even be duplicated, so normally information is buffered and interpreted as it is received. It would be very expensive to reconstruct all messages at network level. So that is normally up to the receiver, if it wants to do that.
In your case If what you want is print the input stream I would recommend creating a custom InputStream, which receives the original InputStream and whenever it is read it prints the read value and returns it at the same time. For example:
class MyInputStream extends InputStream {
InputStream original = null;
public MyInputStream(InputStream original) {
this.original = original;
}
#Override
public int read() throws IOException {
int c = original.read();
System.out.printf("%c", c);
return c;
}
}
Then wrap your original InputStream with that:
.
.
.
InputStream myIs = new MyInputStream(is);
Reader r = new InputStreamReader(myIs);
.
.
.
Hope it helps.
InputStreamReader does not support reset(). Also, you did not call mark(0) before.
What you could do is wrap your reader in a BufferedReader of a sufficient size so that reset is supported. If you cannot do that, then you should try to open a new connection to your URL.

Good connection establishment

I know that there is a good variant to use Scanner object when you need to get data from server during connetion. But I have question about the following code snippet:
public void sendMessage(String message) {
try {
OutputStream os = socket.getOutputStream();
try {
byte[] buffer;
buffer = message.getBytes();
os.write(buffer);
} finally {
os.close();
}
InputStream is = socket.getInputStream();
try {
StringBuffer data = new StringBuffer();
Scanner in = new Scanner(is);
while (in.hasNext()) {
data.append(in.next());
}
System.out.println(data.toString());
} finally {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
I'm confused by the snippet where Scanner gets data from InputStream, because it starts just after I send a message to the Server. Is it fair to suppose that data from the Server won't be in InputStream immediatelly after sending message to it?
Please, give me an advice, what is the best way to make reading data from InputStream in such case and what I should to take into consideration?
The InputStream.read() method called by Scanner blocks until there is some data available. So you don't have to worry about the response time of the server.
See: http://download.oracle.com/javase/6/docs/api/java/net/Socket.html#getInputStream()
The code is invalid. All it does is read as much input as can be read without blocking. There is no implication that what has been read is a complete message, or corresponds to a single write() invocation at the sender, etc. If you want messages in TCP/IP you must implement them yourself, with a length word prefix, a self-describing protocol such as Object Serialization or XML, etc. etc.

Categories