java file receive stops - java

I'm using sockets for file transfer in java.
Here is the Client code
for(int i = 0;i < fileList.size();i++) {
String filename = (String)fileList.get(i);
RequestFile(filename);
try {
BufferedOutputStream fileWriter = new BufferedOutputStream(
new FileOutputStream(
new File(PROGRAM_PATH + "/" +
filename)));
int packet;
int count = 0;
while((packet = fileReader.read()) != -1) {
fileWriter.write(packet);
count++;
}
System.out.println(filename + " receiver complete. (count : " + count + ")");
fileWriter.flush();
fileWriter.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
And here is the Server code
public void SendFile(String filename) {
try {
fileReader = new BufferedInputStream(new FileInputStream(CLIENT_PATH + "/" + filename));
int packet;
int count = 0;
while((packet = fileReader.read()) != -1) {
count++;
fileWriter.write(packet);
}
fileWriter.write(-1);
System.out.println(count);
fileReader.close();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
When I checked the server's count, it was 635. It means the server had sent data 635 times.
However, the client's print count is only 512. (from 0 to 511) I think it's stopped at read(), because
System.out.println(filename + " receiver complete. (count : " + count + ")");
is not printed. Can someone tell me the reason and solution?

At the server side you can't send a byte with value -1 to the client. This line:
fileWriter.write(-1);
It does not do what you want. The write() method will take the lowest 8 bits of the parameter and send that as one byte (which in this case will be 0xff). At the client side fileReader.read() will receive this as 0xff (of type int) and not as -1 (of type int).
-1 is a special value indicating that end of stream has been reached. It is not a valid data to be written or read. If you send -1, the client will read that as 0xff=255. The values that can be sent and received is 0..255 both inclusive. Again, -1 is a special value for end-of-stream.
At the server side you don't flush or close the output stream. That might explain the difference (data hold in the buffer might not get through to the client).

Related

Handling binary packets

I coded this packet handler but I can imagine scenarios in which it will get stuck or won't be able to read incomplete data. My questions are:
Should I use two buffers, one for the current incoming data and other to append incomplete data to?
I'm being stupidly over-complicated?
Code:
byte[] buffer;
int bufferLength;
int bytesRead;
buffer = new byte[1024];
while (bluetoothConnected) {
try {
// Wait for packet header
if (mmInStream.available() >= 8) {
bufferLength = mmInStream.read(buffer);
bytesRead = 0;
// Parse every packet
while (true) {
int commandType = ByteBuffer.wrap(buffer, 0, 2).order(ByteOrder.LITTLE_ENDIAN).getShort();
int payloadSize = ByteBuffer.wrap(buffer, 2, 2).order(ByteOrder.LITTLE_ENDIAN).getShort();
int packetSize = PACKET_HEADER_SIZE + payloadSize;
// Break if payload is incomplete
if (bufferLength < (bytesRead + packetSize)) {
// Append to other buffer
break;
}
byte[] packet = new byte[packetSize];
System.arraycopy(buffer, bytesRead, packet, 0, packetSize);
parsePacketSequence(socket, packet);
bytesRead += packetSize;
// Break if all bytes are read
if (bufferLength == bytesRead)
{
break;
}
// Break if more bytes are needed
// Packet header incomplete
if ((bufferLength - bytesRead) < PACKET_HEADER_SIZE)
{
// Append to other buffer
break;
}
}
}
}
catch (IOException e) {
bluetoothConnected = false;
Log.d(TAG, "Error " + e);
break;
}
}
Should I use two buffers, one for the current incoming data and other to append incomplete data to?
No.
I'm being stupidly over-complicated?
Yes.
Here's a simple version using DataInputStream:
DataInputStream din = new DataInputStream(mmInStream);
while (bluetoothConnected) {
try {
// Read packet header
int commandType = swap(din.readShort());
int payloadSize = swap(din.readShort());
int packetSize = PACKET_HEADER_SIZE + payloadSize;
byte[] packet = new byte[packetSize];
din.readFully(packet);
parsePacketSequence(socket, packet);
}
catch (IOException e) {
bluetoothConnected = false;
Log.d(TAG, "Error " + e);
break;
}
}
The swap() method which converts a short in litte-endian byte order to Java byte order is left as an exercise for the reader.
NB I don't see how parsePacketSequence() can work if it doesn't know commandType.
E&OE

Incorrectly reading int from binary file Java

I'm trying to read a date (set of 6 integers) and temperature (double) from binary .dat file.
After multiple tries I finally got to the stage where the file is working, but it's returning int in the format I cannot recognize. Eg. date 2017-03-02 11:33 , and temperature 3.8 is read as:
Measure : 515840-1024-1024 2816 8512 241591910
temperature: 1.9034657819129845E185
Any ideas, how to change the code?
public void readFile() {
try {
DataInputStream dis = null;
BufferedInputStream bis = null;
try {
FileInputStream fis = new FileInputStream(fileLocation);
int b;
bis = new BufferedInputStream(fis);
dis = new DataInputStream(fis);
while ((b = dis.read()) != -1) {
System.out.println("Measure : " + dis.readInt() + "-"
+ dis.readInt() + "-" + dis.readInt() + " " +
dis.readInt() + " " + dis.readInt() + " "
+ dis.readInt() + " Temperature: "+ dis.readDouble());
}
} finally {
dis.close();
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (EOFException f) {
f.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} // readFile
while ((b = dis.read()) != -1) {
The problem is here. This reads and discards a byte of the file on every iteration, so all subsequent reads are out of sync.
The correct way to loop with a DataInputStream or ObjectInputStream is with a while (true) loop, and terminating it when read() returns -1, readLine() returns null, or readXXX() for any other X throws EOFException.
Note that you don't normally need to log or print a stack trace on EOFException, as it's a normal loop termination condition ... unless you had reason to expect more data, e.g. your file started with a record count that you haven't reached yet, which might indicate that the file was truncated and therefore corrupt.

How I can send an String and an Integer over a socket?

I have 2 buttons in my client with a button listener each.
In my firt button listener I am sending a String over the socket and I am getting back an array of integers after it is spanwed. No problem there. Here is my code.
public void rollDice() {
try {
DataOutputStream sout1 = new DataOutputStream(socket.getOutputStream());
String line = "dice";
PrintStream out1 = new PrintStream(sout1);
out1.println(line);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
With the second listener I want t send first a string to put the server into the right state, and after I want to send an integer to continue the process. Here is my code but it doesn't seem to work. Server is printing a random number, even if I send a "2".
public void sendDice() {
try {
DataOutputStream sout2 = new DataOutputStream(socket.getOutputStream());
String line = "pick";
PrintStream out2 = new PrintStream(sout2);
out2.println(line);
out2.write(diceListLength);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
Here is the server's side.
public void run() {
boolean running = true;
try {
// Create streams for reading / writing lines of text to the socket
DataInputStream input = new DataInputStream(s.getInputStream());
DataInputStream inputInt = new DataInputStream(s.getInputStream());
ObjectOutputStream output = new ObjectOutputStream(s.getOutputStream());
// Print a message:
System.out.println("\nClient from: " + s.getInetAddress() + " port " + s.getPort());
while(running) {
String st = input.readLine();
if (st.equals("dice")) {
for (int i = 0; i < diceRolled.length - number; i++) {
diceRolled[i] = (int) ( 1 + Math.random() * 6);
System.out.print(diceRolled[i] + " ");
}
output.writeObject(diceRolled);
output.reset();
} else if (st.equals("pick")) {
number = inputInt.readInt();
System.out.print(number);
}
}
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
// Always be sure to close the socket
} finally {
try {
if (s != null) {
System.out.println(s.getLocalSocketAddress() + " closed.");
s.close();
}
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Try setting autoFlush on the PrintStream when you create it... a single integer will not be sent until newline or buffer full.
From java's documentation
autoFlush - A boolean; if true, the output buffer will be flushed whenever a byte array is written, one of the println methods is invoked, or a newline character or byte ('\n') is written
Also useful:
Use line-based messaging, i.e. the second message type can be "pick:4" (check with st.startsWith("pick")) and then parse the integer. With your code, you can easily end up loosing state. (Single-line messages are "pseudo-atomic").
Don't create DataInputStreams in every listener method, make them object variables (same for PrintStreams...). There's no need to (re)create objects in every click.

Java SSL connection returns previous reply

I'm using an SSL connection to connect with a server (which i have no control over and no access to it's code, could be it's fault, but i wanna be sure), when i send the data (a byte array) for the first time i get the correct response, but in subsequent sends i get the response expected by the previous send. for example, let's say if i send x, i expect the server to reply x, y to y, z to z, etc...
when the app starts, i call x, and get x. but then i call y and get x, call z and get y, call x and get z, etc...
here's the generic code implemented for each command to send and receive (bytes is initiated with a predetermined set of bytes to simulate, say, command x)
byte[] bytes = new byte[6];
if(socket == null || !socket.isConnected() || socket.isClosed())
try {
getSocket(localIp);
} catch (IOException e1) {
e1.printStackTrace();
}
if (socket == null || !socket.isConnected()) {
try {
getSocket(globalIp);
} catch (IOException e1) {
e1.printStackTrace();
return null;
}
}
byte[] recievedBytes = null;
String sentBString = "sendGetConfig: ";
for (int i = 0; i < bytes.length; i++) {
sentBString += String.valueOf(bytes[i]) + ", ";
}
System.out.println(sentBString);
if (socket != null){
try {
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
os.write(bytes);
DataInputStream is = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
int tries = 0;
while (tries < 20 && (recievedBytes == null || recievedBytes.length == 0)) {
if (is.markSupported()) {
is.mark(2048);
}
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
try {
nRead = is.read(data, 0, data.length);
buffer.write(data, 0, nRead);
} catch (Exception e) {
}
buffer.flush();
recievedBytes = buffer.toByteArray();
if (recievedBytes.length == 0)
is.reset();
}
is.close();
os.close();
socket.close();
}
}
i know the implementation of the read is not perfect, its the result of a workaround i did because the server does not send any end of stream indication and so any read command implemented in a loop results in a timeout exception
any help will be greatly appreciated
the server does not send any end of stream indication
Of course the server sends an EOS indication. The problem is that you're completely ignoring it. When the peer has closed the connection and there is no more pending data to be read, read() returns -1.
and so any read command implemented in a loop results in a timeout exception
Nonsense.
The correct form of your loop is as follows:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
substituting your own variable names as required.
The reason you keep reading the same data is because you keep resetting the stream to the same point. Just throw your mark() and reset() calls away.

How to trap ftp success/failure in sun.net.ftp.FtpClient?

I want to know if really 'put' has succeeded in putting the file to destination. If for any reason the file is not put in destination [maybe due to problems in destination server like space constraint, etc] I need to know that.
Code:
private static boolean putFile(String m_sLocalFile, FtpClient m_client) {
boolean success = false;
int BUFFER_SIZE = 10240;
if (m_sLocalFile.length() == 0) {
System.out.println("Please enter file name");
}
byte[] buffer = new byte[BUFFER_SIZE];
try {
File f = new File(m_sLocalFile);
int size = (int) f.length();
System.out.println("File " + m_sLocalFile + ": " + size + " bytes");
System.out.println(size);
FileInputStream in = new FileInputStream(m_sLocalFile);
OutputStream out = m_client.put(f.getName());
int counter = 0;
while (true) {
int bytes = in.read(buffer);
if (bytes < 0)
break;
out.write(buffer, 0, bytes);
counter += bytes;
System.out.println(counter);
}
out.close();
in.close();
} catch (Exception ex) {
System.out.println("Error: " + ex.toString());
}
return success;
}
I would expect it to throw an IOException. Do you have any reason to believe it doesn't? But you shouldn't be using that class directly, you should be using an ftp: URL and its URLConnection class to do the I/O with, after calling setDoOutput(true).

Categories

Resources