Java Socket Programming-Transferring File through Socket in Java

So far we have seen the fundamentals of Java Networking .We have seen TCP and UDP  modes .We discussed a simple chat application in Java with Socket programming . In this chapter we are discussing how the transferring file through socket in Java is  happening with suitable example. In this chapter we are discussing it with TCP.(If interested , see the file transfer using UDP too).The exaple can be used to transfer files of small and medium sizes .we can send all types of files like .jpg,.mp3,.mp4 etc.

Transferring File through Socket in Java

We have a server as well as client. We need to send a file from client to server.In this example we are sending the file between client and server in a hand shaking way.The working of the  client server system I have developed(This may not be the ideal way . A better approach is discussed here) can be summarized as below:

1)Once a connection is established between client and server, the client sends a request ‘May I send ?’

2)After getting the request the server gives the response ‘Yes ,You can  ‘  back to the client.

3)After receiving the response , client sends the output directory and then  file header with file size.Output directory and file with specified extension will be created.

4)After receiving the file header, server sends ‘File header received …Send File’ back to the client.

5)After getting it  client sends  the file as byte stream.

6)When the file is completely received  at server side , server sends ‘File Received’  message.Also it is closing the file streams.

7)After getting the message , the client closes the communication channel .Application also exits.

Now let us examine the server code.

The ServerMain.java  is the main class.

ServerMain.java

public class ServerMain {

public ServerMain(){

}
public static void main(String[] args){
DirectoryRcr dirRcr = new DirectoryRcr();
}
}

DirectoryRcr.java is the class contains the logic.

DirectoryRcr.java

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

public class DirectoryRcr {

String request = "May I send?";
String respServer = "Yes,You can";
String dirResponse = "Directory created...Please send files";
String dirFailedResponse = "Failed";
String fileHeaderRecvd = "File header received ...Send File";
String fileReceived = "File Received";
Socket socket = null;
OutputStream ioStream = null;
InputStream inStream = null;
boolean isLive = false;
int state = 0;
final int initialState = 0;
final int dirHeaderWait = 1;
final int dirWaitState = 2;
final int fileHeaderWaitState = 3;
final int fileContentWaitState = 4;
final int fileReceiveState = 5;
final int fileReceivedState = 6;
final int finalState = 7;
byte[] readBuffer = new byte[8192];
long fileSize = 0;
String dir = "";
private File currentFile = null;
FileOutputStream foStream = null;
int fileCount = 0;

public DirectoryRcr() {
acceptConnection();
}

private void acceptConnection() {
try {
ServerSocket server = new ServerSocket(3339);
socket = server.accept();
isLive = true;
ioStream = socket.getOutputStream();
inStream = socket.getInputStream();
state = initialState;
startReadThread();

} catch (IOException io) {
io.printStackTrace();
}
}

private void startReadThread() {
Thread readRunnable = new Thread() {
public void run() {
while (isLive) {
try {
int num = inStream.read(readBuffer);
if (num > 0) {
byte[] tempArray = new byte[num];
System.arraycopy(readBuffer, 0, tempArray, 0, num);
processBytes(tempArray);
}
// sleep(100);

} catch (SocketException s) {

} catch (IOException e) {
e.printStackTrace();
/*}catch (InterruptedException i){
i.printStackTrace();*/
}
}
}
};
Thread readThread = new Thread(readRunnable);
readThread.start();
}

private void processBytes(byte[] buff) {
if (state == fileReceiveState || state == fileContentWaitState) {
//write to file

writeToFile(buff);
if (state == fileContentWaitState)
state = fileReceiveState;
fileSize = fileSize - buff.length;
if (fileSize == 0) {
state = fileReceivedState;
try {
foStream.close();
} catch (IOException io) {
io.printStackTrace();
}
sendResponse(fileReceived);
System.out.println("Received");
closeSocket();

}
} else {
parseToUTF(buff);
}

}
public void closeSocket(){
try {
socket.close();
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
}

private void parseToUTF(byte[] data) {
try {
String parsedMessage = new String(data, "UTF-8");
System.out.println(parsedMessage);
setResponse(parsedMessage);
} catch (UnsupportedEncodingException u) {
u.printStackTrace();
}

}

private void setResponse(String message) {
if (message.trim().equalsIgnoreCase(request) && state == initialState) {
sendResponse(respServer);
state = dirHeaderWait;

} else if (state == dirHeaderWait) {
if (createDirectory(message)) {
sendResponse(dirResponse);
state = fileHeaderWaitState;
} else {
sendResponse(dirFailedResponse);
System.out.println("Error occurred...Going to exit");
System.exit(0);
}

} else if (state == fileHeaderWaitState) {
createFile(message);
sendResponse(fileHeaderRecvd);
state = fileContentWaitState;
} else if (message.trim().equalsIgnoreCase(dirFailedResponse)) {
System.out.println("Error occurred ....");
System.exit(0);
}

}

private void sendResponse(String resp) {
try {
sendBytes(resp.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}

private boolean createDirectory(String dirName) {
boolean status = false;
dir = dirName.substring(dirName.indexOf("$") + 1, dirName.indexOf("#"));
System.out.println("Directory name = " + dir);
if (new File(dir).mkdir()) {
status = true;
System.out.println("Successfully created directory");
} else if (new File(dir).mkdirs()) {
status = true;
System.out.println("Directories were created");

} else if (new File(dir).exists()) {
status = true;
System.out.println("Directory exists");
} else {
System.out.println("Could not create directory");
status = false;
}

return status;
}

private void createFile(String fileName) {

String file = fileName.substring(fileName.indexOf("&") + 1, fileName.indexOf("#"));
String lengthFile = fileName.substring(fileName.indexOf("#") + 1, fileName.indexOf("*"));
fileSize = Integer.parseInt(lengthFile);
File dstFile = new File(dir + "/" + file);
try {
foStream = new FileOutputStream(dstFile);
} catch (FileNotFoundException fn) {
fn.printStackTrace();
}

}

private void writeToFile(byte[] buff) {
try {
foStream.write(buff);
} catch (IOException io) {
io.printStackTrace();
}
}

private void sendBytes(byte[] dataBytes) {
synchronized (socket) {
if (ioStream != null) {
try {
ioStream.write(dataBytes);
} catch (IOException io) {
io.printStackTrace();
}
}
}

}

}

Now lets see the client side code.

ClientMain.java

import java.io.IOException;
import java.net.Socket;
public class ClientMain {
private DirectoryTxr transmitter = null;
Socket clientSocket = null;
private boolean connectedStatus = false;
private String ipAddress;
String srcPath = null;
String dstPath = "";

public ClientMain() {

}

public void setIpAddress(String ip) {
this.ipAddress = ip;
}

public void setSrcPath(String path) {
this.srcPath = path;
}

public void setDstPath(String path) {
this.dstPath = path;
}

private void createConnection() {
Runnable connectRunnable = new Runnable() {
public void run() {
while (!connectedStatus) {
try {
clientSocket = new Socket(ipAddress, 3339);
connectedStatus = true;
transmitter = new DirectoryTxr(clientSocket, srcPath, dstPath);
} catch (IOException io) {
io.printStackTrace();
}
}

}
};
Thread connectionThread = new Thread(connectRunnable);
connectionThread.start();
}

public static void main(String[] args) {
ClientMain main = new ClientMain();
main.setIpAddress("localHost");
main.setSrcPath("E:/temp/songs");
main.setDstPath("C:/TCPServer");
main.createConnection();

}
}

Remeber , the srcPath should be present in the client and it should  contain one file with any extension . The path can be different for different platforms.Please change accordingly. The DirectoryTxr.java contains the logic for sending file.

DirectoryTxr.java

import java.io.*;
import java.net.Socket;

public class DirectoryTxr {

Socket clientSocket = null;
String srcDir = null;
String dstDir = null;
byte[] readBuffer = new byte[1024];
private InputStream inStream = null;
private OutputStream outStream = null;
int state = 0;
final int permissionReqState = 1;
final int initialState = 0;
final int dirHeaderSendState = 2;
final int fileHeaderSendState = 3;
final int fileSendState = 4;
final int finishedState = 5;
private boolean isLive = false;
private int numFiles = 0;
private int filePointer = 0;
String request = "May I send?";
String respServer = "Yes,You can";
String dirResponse = "Directory created...Please send files";
String fileHeaderRecvd = "File header received ...Send File";
String fileReceived = "File Received";
String dirFailedResponse = "Failed";
File[] opFileList = null;

public DirectoryTxr(Socket clientSocket, String srcDir, String dstDir) {

try {
this.clientSocket = clientSocket;
inStream = clientSocket.getInputStream();
outStream = clientSocket.getOutputStream();
isLive = true;
this.srcDir = srcDir;
this.dstDir = dstDir;
state = initialState;
readResponse(); //starting read thread
sendMessage(request);
state = permissionReqState;
} catch (IOException io) {
io.printStackTrace();
}

}

private void sendMessage(String message) {
try {
sendBytes(request.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}

/**
* Thread to read response from server
*/
private void readResponse() {
Runnable readRunnable = new Runnable() {
public void run() {
while (isLive) {
try {
int num = inStream.read(readBuffer);
if (num > 0) {
byte[] tempArray = new byte[num];
System.arraycopy(readBuffer, 0, tempArray, 0, num);
processBytes(tempArray);
}
} catch (IOException io) {
io.printStackTrace();
isLive = false;
}
}
}
};
Thread readThread = new Thread(readRunnable);
readThread.start();

}

private void sendDirectoryHeader() {
File file = new File(srcDir);
if (file.isDirectory()) {
try {
String[] childFiles = file.list();
numFiles = childFiles.length;
String dirHeader = "$" + dstDir + "#" + numFiles + "&";
sendBytes(dirHeader.getBytes("UTF-8"));
} catch (UnsupportedEncodingException en) {
en.printStackTrace();
}
} else {
System.out.println(srcDir + " is not a valid directory");
}
}

private void sendFile(String dirName) {
File file = new File(dirName);
if (file.isDirectory()) {
File[] opFileList = file.listFiles();
File opFile = opFileList[0];
try {
DataInputStream diStream = new DataInputStream(new FileInputStream(opFile));
int len = (int) opFile.length();
/*if (len > Integer.MAX_VALUE) {
System.out.println("Cannot sent ...." + file.getName());

return;
}*/
byte[] fileBytes = new byte[len];
int read = 0;
int numRead = 0;
while (read < fileBytes.length && (numRead = diStream.read(fileBytes, read, fileBytes.length - read)) >= 0) {
read = read + numRead;
}
sendBytes(fileBytes);

} catch (FileNotFoundException f) {
f.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}

}

private void sendHeader(String fileName) {
try {
File file = new File(fileName);
if (file.isDirectory())
return;//avoiding child directories to avoid confusion
//if want we can sent them recursively
//with proper state transitions

String header = "&" + fileName + "#" + file.length() + "*";
sendHeader(header);

sendBytes(header.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}

private void sendBytes(byte[] dataBytes) {
synchronized (clientSocket) {
if (outStream != null) {
try {
outStream.write(dataBytes);
outStream.flush();
} catch (IOException io) {
io.printStackTrace();
}
}
}

}

private void processBytes(byte[] data) {
try {
String parsedMessage = new String(data, "UTF-8");
System.out.println(parsedMessage);
setResponse(parsedMessage);
} catch (UnsupportedEncodingException u) {
u.printStackTrace();
}
}

private void setResponse(String message) {
if (message.trim().equalsIgnoreCase(respServer) && state == permissionReqState) {
state = dirHeaderSendState;
sendDirectoryHeader();

} else if (message.trim().equalsIgnoreCase(dirResponse) && state == dirHeaderSendState) {
state = fileHeaderSendState;
if (LocateDirectory()) {
createAndSendHeader();
} else {
System.out.println("Vacant or invalid directory");
}

} else if (message.trim().equalsIgnoreCase(fileHeaderRecvd) && state == fileHeaderSendState) {
state = fileSendState;
sendFile(srcDir);
state = finishedState;

} else if (message.trim().equalsIgnoreCase(fileReceived) && state == finishedState) {
System.out.println("Successfully sent");
System.exit(0);
//closeSocket();
} else if (message.trim().equalsIgnoreCase(dirFailedResponse)) {
System.out.println("Going to exit....Error ");
System.exit(0);
}

}

private void closeSocket() {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

private boolean LocateDirectory() {
boolean status = false;
File file = new File(srcDir);
if (file.isDirectory()) {
opFileList = file.listFiles();
if (opFileList.length <= 0) { System.out.println("No files found"); } else { status = true; } } return status; } private void createAndSendHeader() { File opFile = opFileList[filePointer]; String header = "&" + opFile.getName() + "#" + opFile.length() + "*"; try { sendBytes(header.getBytes("UTF-8")); filePointer++; } catch (UnsupportedEncodingException e) { } } }

Output

Please refresh the output path in server after the running of both client and server is over.

Remember,  in this example we are converting a file to bye array directly and sending through socket.If our file size is too large ,  heap over flow will happen.So the example we discussed here is applicable only to small and medium sized files.

See related topics:

Java networking overview

TCP  example

UDP example

Chat application in Java

Sending object through sockets

Transferring files through socket

4 thoughts on “Java Socket Programming-Transferring File through Socket in Java

  1. Mahdi Alavi Reply

    Salaam, Thanks a lot for this topic. It should be better if you break the code in small learning parts!

    • Bijoy Post authorReply

      Thank you very much for your positive comment

Leave a Reply

Your email address will not be published. Required fields are marked *