I have a problem to send a file(not necessarily a txt file) over a socket.I have 2 classes:Server,Client.When I read from a socket output stream and want to write the bytes in a file,it looks working but when i open the file it has nothing.(corrupted showing the size=0 kb).I also want it to transfer all kind of file over a socket.I don't want to use appache commons net.
Here is my code
Server class
FileOutputStream toFile1 = new FileOutputStream(f);
BufferedOutputStream toFile= new BufferedOutputStream(toFile1);
BufferedInputStream bis=new BufferedInputStream(incoming.getInputStream());
byte[]buffer=new byte[2048];
int bytesRead=0;
while((bytesRead = bis.read(buffer)) >= 0)
{
toFile.write(buffer, 0, bytesRead);
}
toFile.close();
toFile1.close();
bis.close();
out.println("226 Connection Closed");
out.flush();
}
Client class
BufferedOutputStream output = new BufferedOutputStream(socket.getOutputStream());
byte[] buffer = new byte[60*2024];
int bytesRead = 0;
while ((bytesRead = input.read(buffer,0,60*1024)) != -1) {
output.write(buffer, 0, bytesRead);
}
The only way that can happen with that code is if you are sending a zero length file, or maybe reading from a file input stream that is already positioned at EOF, or else you are looking at the wrong file afterwards.
Related
I'm trying to transfer some image files from an android phone, over a socket, to a server. The only way I've found to do this on android so far is using a FileInputStream to read the image as a byte array and send this over the socket to be reconstructed on the server side. This works well, unfortunately Android (or java?) does not allow Metadata, in my case exif data, to be included in a FileInputStream. This means that my exif data is missing once the images are on the server.
I've tried to solve this issue using both ExifInterface, which doesn't seem to be able to read a lot of the exif data I need, and the Metadata library. The metadata library does seem to get all the exif data I want but I can't figure out how to write it out as bytes that can be sent over my stream, it only has a toString which gets rid of some of the data that needs to be transferred.
Ideally I'd love a way to transfer the file with it's metadata, however I'd be happy with a way to turn Metadata tags into bytes which I can add to my socket's output stream.
Here is the code which uploads files over the socket
FileInputStream in = new FileInputStream(lastSavedPath);
byte[] buffer = new byte[1024];
int length = 0;
while ((length = in.read(buffer, 0, buffer.length)) != -1){
outputStream.write(buffer, 0, length);
}
ExifInterface exifInterface = new ExifInterface(lastSavedPath);
Metadata metadata = ImageMetadataReader.readMetadata(new File(lastSavedPath));
for (Directory directory : metadata.getDirectories()){
for (Tag tag : directory.getTags()){
Log.d("Socket Listener", tag.toString());
if (tag.toString().indexOf("Exif")>=0)
Log.d("Socket exif", "Data"+exifInterface.getAttribute(tag.getTagName()));
}
}
outputStream.flush();
Log.d("Socket Listener", "Data has been sent");
in.close();
socket.close();
The issue here wasn't with android at all. I had read in another thread that the android FileInputStream did not include metadata but that was not the case. I believe now the issue was in my server side code. I've fixed the issue with the following code:
Server side (Needs to be in a try catch):
socket = new Socket(args[0], 8888);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataInputStream = new DataInputStream(socket.getInputStream());
dataOutputStream.writeUTF(args[1]);
System.out.println("Saving image");
FileOutputStream fileout = new FileOutputStream("/home/jamie/Documents/UMDSummer16/Thermal/TemporalAnalysisSensor/SocketTest/"+args[2]);
byte[] bytes = new byte[1024];
int count;
while ((count = dataInputStream.read(bytes)) > 0){
fileout.write(bytes);
}
fileout.close();
dataInputStream.close();
Android side (also in a try catch):
FileInputStream in = new FileInputStream(lastSavedPath);
byte[] buffer = new byte[1024];
int length = 0;
while ((length = in.read(buffer, 0, buffer.length)) != -1) {
outputStream.write(buffer, 0, length);
}
outputStream.flush();
Log.d("Socket Listener", "Data has been sent");
in.close();
socket.close();
I'm in the midst of trying to send a file, and in particular large files, from server to client. I can send small files but atm large files do not work.
Server
Socket socket = serverSocket.accept();
byte[] data = new byte[(int)myFile.length()];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(data, 0, data.length);
OutputStream oStream = socket.getOutputStream();
oStream.write(data, 0, data.length);
Client
byte[] data = new byte[4096];
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("output.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(data, 0, data.length);
int counter = bytesRead;
// while (-1 != (bytesRead = is.read(data, 0, data.length)))
// {
// bos.write(data, 0, bytesRead);
// }
bos.write(data, 0, bytesRead);
With this code i'm able to transfer a simple text file successfully. With the commented out section uncommented (and excluding the last line) i thought i'd still be able to send a simple text file and in addition large files like a 200mb video. Obviously, it failed and here i am. Hope someone could give me a hand.
EDIT: Error with while loop (and no last line) is that nothing is written in the txt file
Get rid of the first read and the last write and just use the code that is commented out. That's the only code that actually works.
I am trying to send Files with JAVA. My problem is that the client never knows if the end of the file is reached or not. So the while loop of the Client never ends. Please help me.
Server (sends Data to Client)
File myFile = new File("C://LEGORacers.exe");
byte[] mybytearray = new byte[(int) myFile.length()];
BufferedInputStream bis = null;
OutputStream os = null;
bis = new BufferedInputStream(new FileInputStream(myFile));
bis.read(mybytearray, 0, mybytearray.length);
os = socket.getOutputStream();
os.write(mybytearray, 0, mybytearray.length);
os.flush();
bis.close();
Client (gets Data from Server)
byte[] buf = new byte[1024];
InputStream is = null;
int bytesRead = 0;
is = client.getInputStream();
FileOutputStream fos = null;
fos = new FileOutputStream("C://copy.exe");
BufferedOutputStream bos = new BufferedOutputStream(fos);
try {
while (-1 != (bytesRead = is.read(buf, 0, buf.length))) {
// This while loop never ends because is.read never returns -1 and I don't know why...
bos.write(buf, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
is.close();
bos.flush();
bos.close();
fos.close();
}
Did you close your OutputStream on your Server? If not, your loop might be perpetually setting bytesRead to 0, so you may need to close that stream.
If you need the Server's OutputStream to still be open after sending data, you could also send the size of the data in bytes at the beginning of the stream, and loop until you have all of the bytes the Server indicates it will send.
Close the socket output stream on the server. Flushing doesn't terminate the stream, which is what you need to do to send the signal that the server is done writing. From what you posted, I don't see where you close the output stream on the server side.
I have one client and one server communicating with each other via TCP sockets. The client would like to transfer two files and some description of the files to the server. I would like to design a protocol that once a socket is established between the client and the server, the server would expect to receive the file description first and then the two files. Currently, with the following code, the server can receive the description but fails to distinguish the two files (the two files transferred from the client are merged into one single file at the server). I found similar threads on this issue. But they separately discussed "file info + one single file" and "multiple file without pre-file-info". Please give me a hint on resolving this issue. Many thanks.
Sever-side code
dis = new DataInputStream(clientSocket.getInputStream());
callInfo = dis.readUTF();
callInfos = callInfo.split(" ");
FileOutputStream fos = new FileOutputStream(File1);
byte[] buffer = new byte[clientSocket.getReceiveBufferSize()];
int bytesReceived = 0;
while ((bytesReceived = dis.read(buffer)) > 0)
fos.write(buffer, 0, bytesReceived);
fos.flush();
fos.close();
fos = new FileOutputStream(File2);
while ((bytesReceived = dis.read(buffer)) > 0)
fos.write(buffer, 0, bytesReceived);
fos.flush();
fos.close();
Client-side code
String fileIno = "fileIno";
byte[] buffer = new byte[socket.getSendBufferSize()];
int bytesRead = 0;
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(fileInfo);
FileInputStream file = new FileInputStream(File1);
while ((bytesRead = file.read(buffer)) > 0)
dos.write(buffer, 0, bytesRead);
dos.flush();
file.close();
file = new FileInputStream(File2);
while ((bytesRead = file.read(buffer)) > 0)
dos.write(buffer, 0, bytesRead);
dos.flush();
file.close();
Design your protocol such that the "file description" information includes the number of bytes in each file. Then you will know where the first file begins and ends and where the second file begins and ends.
I have a Java server class like this:
ServerSocket servsock = new ServerSocket(63456);
boolean read = false;
while (!read) {
Socket sock = servsock.accept();
int length = 1024;
byte[] mybytearray = new byte[length];
OutputStream os = sock.getOutputStream();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
while (true) {
int i = bis.read(mybytearray, 0, mybytearray.length);
if (i == 1) {
break;
}
os.write(mybytearray, 0, mybytearray.length);
os.flush();
}
sock.close();
read = true;
}
`
And the client is like this:
Socket sock = new Socket("127.0.0.1", 63456);
byte[] mybytearray = new byte[1024];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream("C:/tmp/NEWtmp.rar");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
while(bytesRead != -1 ) {
bos.write(mybytearray, 0, bytesRead);
bytesRead = is.read(mybytearray, 0, mybytearray.length);
}
bos.close();
sock.close();
One question is: Why the loop does not stop at the end of the file?
A second question would be, why is also so slow?
It does not stop because
if (i == 1) {
in your server source should be
if (i == -1) {
Or, if you want to be really safe:
if (i <= 0) {
Also, you risk data corruption with this line:
os.write(mybytearray, 0, mybytearray.length);
You should change this to:
os.write(mybytearray, 0, i);
On performance -- move the os.flush(); call to outside the while loop. When you flush a network stream, you are forcing it to dispatch any buffered data to the network. This is forcing the network layer to send and acknowledge 1024-byte TCP payloads (larger Ethernet payloads, of course) which is probably significantly smaller than your PMTU. You only need to flush when you are done sending data, or when you want the client to receive the buffered data now. Removing the flush call from each iteration will allow the OS-level network buffer to do its job, and segment the data into as few packets as possible.
Second question - your client reads bytes directly from the raw socket stream. Use the BufferedInputStream/BufferedOutputStream decorators, this should increase performance:
Server Side
BufferedOutputStream os = new BufferedOutputStream(sock.getOutputStream());
Client side
BufferedInputStream is = new BufferedInputStream(sock.getInputStream());
The raw streams are not buffered (AFAIK) so you have to add the buffering manually, if needed.