Java multiple file transfer over socket
You are reading the socket until read()
returns -1. This is the end-of-stream condition (EOS). EOS happens when the peer closes the connection. Not when it finishes writing one file.
You need to send the file size ahead of each file. You're already doing a similar thing with the file count. Then make sure you read exactly that many bytes for that file:
String filename = dis.readUTF();
long fileSize = dis.readLong();
FileOutputStream fos = new FileOutputStream(filename);
while (fileSize > 0 && (n = dis.read(buf, 0, (int)Math.min(buf.length, fileSize))) != -1)
{
fos.write(buf,0,n);
fileSize -= n;
}
fos.close();
You can enclose all this in a loop that terminates when readUTF()
throws EOFException
. Conversely of course you have to call writeUTF(filename)
and writeLong(filesize)
at the sender, before sending the data.
send multiple files with JAVA socket
I've rewritten your send file method slightly so that you can send multiple files, you will need to pass it the DataOutputStream
and close the stream after you have sent all the files you wish to send.
When reading, you should use a DataInputStream
and call long len = dis.getLong()
and then read from the stream the len
bytes, then repeat for the next file. You may find it useful to send the number of files at the start to.
public void sendFile(File file, DataOutputStream dos) throws IOException {
if(dos!=null&&file.exists()&&file.isFile())
{
FileInputStream input = new FileInputStream(file);
dos.writeLong(file.getLength());
System.out.println(file.getAbsolutePath());
int read = 0;
while ((read = input.read()) != -1)
dos.writeByte(read);
dos.flush();
input.close();
System.out.println("File successfully sent!");
}
}
Sending Multiple Files Over a Java Socket
TCP is a byte stream. It has no concept of messages. As such, you need to frame the file data in such a way that the receiver knows where one file ends and the next begins. In this case, you need to send the file size before sending the file data, so the receiver knows how many bytes to expect per file.
Also, you are not paying attention properly to the number of bytes that read()
tells you were actually read each time you call it. You are giving it a large buffer, but there is no guarantee that the entire buffer will be filled up. Especially at the end of a file.
And don't transfer binary file data using strings!
Try something more like this instead:
Client:
File fs = new File("Test1.txt");
long fileLength = fs.length();
InetAddress host = InetAddress.getLocalHost();
Socket clientSocket = new Socket(host, 6789);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
long startTime, endTime, tGap, totalTime = 0;
byte[] sendData = new byte[1024];
int numBytes, filesSent = 0;
while (filesSent < 100) {
FileInputStream fin = new FileInputStream(fs);
long thisFileLength = fileLength;
System.out.println("Sending file to server...");
startTime = System.currentTimeMillis();
outToServer.writeLong(thisFileLength);
while (thisFileLength > 0) {
if (thisFileLength < sendData.length) {
numBytes = fin.read(sendData, 0, (int) thisFileLength);
} else {
numBytes = fin.read(sendData, 0, sendData.length);
}
System.out.println(numBytes);
if (numBytes < 1) {
break;
}
outToServer.write(sendData, 0, numBytes);
thisFileLength -= numBytes;
}
outToServer.flush();
endTime = System.currentTimeMillis();
tGap = endTime - startTime;
totalTime = totalTime + tGap;
System.out.println("Finished run " + filesSent + " with a time of " + tGap);
filesSent++;
fin.close();
if (thisFileLength > 0) {
break;
}
}
clientSocket.close();
System.out.println("I am done to send " + filesSent + " times file, and the average time is: " + (double) totalTime / filesSent);
Server:
ServerSocket welcomeSocket = new ServerSocket(6789);
System.out.println("I am starting now....");
Socket connectionSocket;
connectionSocket = welcomeSocket.accept();
DataInputStream inFromClient = new DataInputStream(new BufferedInputStream(connectionSocket.getInputStream()));
long startTime, endTime, tGap, totalTime = 0;
byte[] receiveData = new byte[1024];
int numBytes, filesRecieved = 0;
while (filesRecieved < 100) {
string filename = "receivedFile" + filesRecieved + ".txt";
FileOutputStream outPut = new FileOutputStream(filename);
startTime = System.currentTimeMillis();
long fileLength = inFromClient.readLong();
System.out.println("OG Bytes: " + fileLength);
while (fileLength > 0) {
if (fileLength < receiveData.length) {
numBytes = inFromClient.read(receiveData, 0, (int) fileLength);
}
else {
numBytes = inFromClient.read(receiveData, 0, receiveData.length);
}
if (numBytes < 1) {
break;
}
try {
outPut.write(receiveData, 0, numBytes);
System.out.println(numBytes);
}
catch (Exception e) {
break;
}
fileLength -= numBytes;
}
outPut.close();
endTime = System.currentTimeMillis();
tGap = endTime - startTime;
totalTime = totalTime + tGap;
System.out.println("I have received " + filename + " using time = " + tGap);
filesRecieved++;
if (fileLength > 0) {
break;
}
}
connectionSocket.close();
System.out.println("I am done now... and the average time used to receive each copy is: " + totalTime / filesRecieved);
welcomeSocket.close();
How to send a list of files over a socket in Java
Here is a full implementation:
Sender Side:
String directory = ...;
String hostDomain = ...;
int port = ...;
File[] files = new File(directory).listFiles();
Socket socket = new Socket(InetAddress.getByName(hostDomain), port);
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(files.length);
for(File file : files)
{
long length = file.length();
dos.writeLong(length);
String name = file.getName();
dos.writeUTF(name);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
int theByte = 0;
while((theByte = bis.read()) != -1) bos.write(theByte);
bis.close();
}
dos.close();
Receiver Side:
String dirPath = ...;
ServerSocket serverSocket = ...;
Socket socket = serverSocket.accept();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
DataInputStream dis = new DataInputStream(bis);
int filesCount = dis.readInt();
File[] files = new File[filesCount];
for(int i = 0; i < filesCount; i++)
{
long fileLength = dis.readLong();
String fileName = dis.readUTF();
files[i] = new File(dirPath + "/" + fileName);
FileOutputStream fos = new FileOutputStream(files[i]);
BufferedOutputStream bos = new BufferedOutputStream(fos);
for(int j = 0; j < fileLength; j++) bos.write(bis.read());
bos.close();
}
dis.close();
I did not test it, but I hope it will work!
Sending multiple files over java sockets
Sorry but I guess you have missed quite some aspects from the design and code. 1st of all you need the protocol, 2nd you need a single source of input stream on target side.
Protocol
In the output stream of local side, I suggest...
- Number of how many files are to be sent.
- Length of file name.
- The file name.
- Length of the file.
- File content
- Repeat 2~5 for the next file if there are any.
So the output stream would be something like:
[num_of_files][file1_name_length][file1_name][file1_size][file1_data][file2_.....]
Target Side
I suggest opening up ONE input stream ONLY and read according to the protocol. Remember flushing and closing each FileOutputStream in each loop.
How to read Socket InputStream for multiple files over byte[] streams?
Make sure you flush
the PrintWriter
before you then write raw bytes directly to the OutputStream
that the PrintWriter
is attached to. Otherwise, you could write any buffer data out of order to the underlying socket.
But more importantly, make sure that if you use buffered reading on the receiving end that you read the file bytes using the same buffer that receives the file name and file size. You should also transfer the File
using smaller fixed chunks, don't allocate a single byte[]
array for the entire file size, that is a waste of memory for large files, and likely to fail.
Server:
try{
byte[] bytes = new byte[1024];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
PrinterWriter pw = new PrintWriter(bos);
pw.println(file.getName()); // Send Filename
pw.println(file.length()); // Send filesize
pw.flush();
int count;
while ((count = fis.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
bos.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client:
try{
byte [] buf = new byte [1024];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
InputStreamReader isr = new InputStreamReader(bis);
String file = isr.readLine(); // Read filename
long fileSize = Long.parseLong(isr.readLine()); // Read Filesize
int count = 0;
while ((fileSize > 0) && (count = bis.read(buf, 0, (int)Math.min(buf.length, fileSize))) > 0){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}
That being said, you might also consider using DataOutputStream.writeLong()
and DataInputStream.readLong()
to send/receive the file size in its original binary format instead of as a textual string:
Server:
try{
byte[] bytes = new byte[1024];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
PrinterWriter pw = new PrintWriter(bos);
pw.println(file.getName()); // Send Filename
pw.flush();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeLong(file.length()); // Send filesize
dos.flush();
int count;
while ((count = fis.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
bos.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client:
try{
byte [] buf = new byte [1024];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
InputStreamReader isr = new InputStreamReader(bis);
String file = isr.readLine(); // Read filename
DataInputStream dis = new DataInputStream(bos);
long fileSize = dis.readLong(); // Read Filesize
int count = 0;
while ((fileSize > 0) && (count = bis.read(buf, 0, (int)Math.min(buf.length, fileSize))) > 0){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}
Related Topics
Why Use Getters and Setters/Accessors
Sort a Map≪Key, Value≫ by Values
Int Division: Why Is the Result of 1/3 == 0
Sort Arraylist of Custom Objects by Property
What Is an Efficient Way to Implement a Singleton Pattern in Java
How Does the Java 'For Each' Loop Work
What Does the 'Static' Keyword Do in a Class
Com.MySQL.Jdbc.Exceptions.Jdbc4.Communicationsexception: Communications Link Failure
How to Declare and Initialize an Array in Java
How to Convert a String to an Int in Java
Calling Awt Frame Methods from Subclass
Calculating the Difference Between Two Java Date Instances
Difference Between Chromedriver and Webdriver in Selenium
"Implements Runnable" VS "Extends Thread" in Java
Assigning Variables With Dynamic Names in Java