This question already has answers here:
Java multiple file transfer over socket
(3 answers)
Closed 7 years ago.
I'm making a communicator with ability to send files.
So far I managed to make text sending working using additional thread (listener).
I'm trying to make the same thing with files, but I don't know, how can I make a file listener - a thread, that detects incoming file, downloads it and listens for another file. Also, I don't know if I'm making my file sender properly. Could you help?
Current sender code:
try {
InputStream in = new FileInputStream(fileToSend);
OutputStream out = fileConn.getOutputStream();
Controller.copyData(in, out);
out.close();
in.close();
} catch (IOException e) {
System.out.println("Problem!");
}
And receiver code:
while (true)
{
try {
InputStream in = socket.getInputStream();
OutputStream out = new FileOutputStream("hi.txt"); //temporary
Controller.copyData(in, out);
out.close();
in.close();
} catch (IOException e) {
System.out.println("Problem!");
}
}
EDIT: I forgot to add my copyData. There it is:
public static void copyData(InputStream in, OutputStream out) throws IOException{
byte[] buf = new byte[8192];
int len = 0;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
}
You can achive tha by just adding to your listening thread option to wait for diffrent messages/options and react accordingly. For example:
private class WaitingThread extends Thread {
volatile boolean awaitsServer = false;
DataInputStream dataInput = new DataInputStream(inputStream);
public void run() {
while (connected) {
int message = 0;
if (awaitsServer == true) {
if (dIn.available() ==0) {
view.setLog("waiting");
} else {
message = dIn.readInt();
switch (tempMessage) {
// TO DO ALL KIND OF COMMUNICATION
case 1:
int filesize = dataInput.readInt();
int bytesRead;
int currentTot = 0;
byte[] bytearray = new byte[filesize];
int len = dataInput.readInt();
FileOutputStream fos = new FileOutputStream(currentlySelectedFile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = dataInput.read(bytearray, 0, bytearray.length);
currentTot = bytesRead;
do {
bytesRead = dataInput.read(bytearray, currentTot,
(len - currentTot));
if (bytesRead >= 0)
currentTot += bytesRead;
} while (currentTot < len);
bos.write(bytearray, 0, currentTot);
bos.close();
}
case 2: //GET TEXT
case 3: //DO SOMETHING ELSE
}}}
Btw you have example how to send files.
Related
I want to receive text files through a socket connection in java, I set up the server end but before I continue with the client I would like to know if the code I made works, except I have no idea how to test this.
Any help would be much appreciated..
EDIT: I know the port is open and listening for requests, what i want is to test what happens if it receives anything, will it create a file from the input and can I test this by simulation(sending a file or bytes i dont know)?
public class Server {
private static int port = 8080;
private static int maxConnections = 100000;
// Listen for incoming connections and handle them
public static void startServer() {
int i = 0;
try {
ServerSocket listener = new ServerSocket(port);
Socket server;
System.out.println("Started server on port:" + port);
while ((i++ < maxConnections) || (maxConnections == 0)) {
RunServer connection;
server = listener.accept();
RunServer conn_c = new RunServer(server);
Thread t = new Thread(conn_c);
t.start();
System.out.println("Created new thread");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class RunServer implements Runnable {
private Socket server;
RunServer(Socket server) {
this.server = server;
}
public void run() {
int bytesRead;
int current = 0;
BufferedOutputStream bufferedOutputStream = null;
FileOutputStream fileOutputStream = null;
DataInputStream clientData = null;
File file = null;
try {
// creating connection.
System.out.println("connected.");
// receive file
byte[] byteArray = new byte[6022386];
System.out.println("Please wait downloading file");
// reading file from socket
InputStream inputStream = server.getInputStream();
file = new File("toread.txt");
clientData = new DataInputStream(inputStream);
fileOutputStream = new FileOutputStream(file);
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
bytesRead = inputStream.read(byteArray, 0, byteArray.length);
current = bytesRead;
do {
bytesRead = inputStream.read(byteArray, current, (byteArray.length - current));
if (bytesRead >= 0)
current += bytesRead;
} while (bytesRead > -1);
bufferedOutputStream.write(byteArray, 0, current);
bufferedOutputStream.flush();
ReaderHelper.readTextFile(file);
} catch (IOException e) {
e.printStackTrace();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (fileOutputStream != null)
fileOutputStream.close();
if (bufferedOutputStream != null)
bufferedOutputStream.close();
if (clientData != null)
clientData.close();
if (server != null)
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Well, your socket will be up on port 8080 right?
You can open your browser and type: http://localhost:8080. The browser will create a connection and the line
server = listener.accept();
will "unlock". If you just wanna test if the socket is listenning it will do. Reading the stream you will see the first message of the HTTP protocol.
At first you have a possible error in a reading loop
byte[] byteArray = new byte[6022386];
//some code
do {
bytesRead = inputStream.read(byteArray, current, (byteArray.length - current));
if (bytesRead >= 0)
current += bytesRead;
} while (bytesRead > -1);
If file length is more than byteArray.length which is possible, then (byteArray.length - current) would be negative.
I suggest you to use smaller array, e.g. byte[] byteArray = new byte[8192]; and read file like this
while ((bytesRead = in.read(byteArray)) > 0 ) {
current += bytesRead;
bufferedOutputStream.write(byteArray, 0, bytesRead);
}
storing it into disk chunk by chunk. And after exiting while loop current will hold total number of read bytes.
Send file from another thread, which will connect to server
Socket clientSocket = new Socket("localhost", Server.port);
BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
DataOutputStream output = new DataOutputStream(clientSocket.getOutputStream());
FileInputStream fileInput = new FileInputStream("fileName");
byte[] buffer = new byte[8192];
while(fileInput.read(buffer) != -1){
output.write(buffer, 0, length);
}
//close resources
I have two projects; one for my server and one for my client, I am able to send images to the server with ease. But I am wondering how would you be able to download that image you just sent to the server back to the client when I press the download button I have created on my client GUI? My code is written in java.
Many Thanks
This is my serverhandler
String fileName;
fileName = "RecievedImageoutreach1.jpg";
DataOutputStream dout = new DataOutputStream(sock.getOutputStream());
//Coding for image transfer
int flag=0,i;
String extn="";
for(i=0; i<fileName.length(); i++)
{
if(fileName.charAt(i)=='.' || flag==1)
{
flag=1;
extn += fileName.charAt(i);
}
}
if(extn.equals(".jpg") || extn.equals(".gif"))
{
try{
File file = new File(fileName);
FileInputStream fin = new FileInputStream(file);
dout.writeUTF(fileName);
byte[] readData = new byte[1024];
while((i = fin.read(readData)) != -1)
{
dout.write(readData, 0, i);
}
//ta.appendText("\nImage Has Been Sent");
dout.flush();
fin.close();
}catch(IOException ex)
{System.out.println("Image ::"+ex);}
}
}
And this is my client
public void download() throws IOException {
// Get input from the server
DataInputStream dis = new DataInputStream (sock.getInputStream());
String str,extn = "";
str = dis.readUTF();
int flag=0,i;
for(i=0;i<str.length();i++)
{
if(str.charAt(i)=='.' || flag==1)
{
flag=1;
extn+=str.charAt(i);
}
}
//**********************reading image*********************************//
if(extn.equals(".jpg") || extn.equals(".gif"))
{
File file = new File("Downloaded"+str);
FileOutputStream fout = new FileOutputStream(file);
//receive and save image from client
byte[] readData = new byte[1024];
while((i = dis.read(readData)) != -1)
{
fout.write(readData, 0, i);
if(flag==1)
{
ta.append("Image Has Been Downloaded");
flag=0;
}
}
fout.flush();
fout.close();
}
}
But when run nothing occurs? i have linked the client method to run when a button is clicked.
I would do something like this:
//Server Handler
File file = new File(fileName);
FileInputStream fin = new FileInputStream(file);
// dout.writeUTF(fileName);
byte[] readData = new byte[1024];
fin.read(readData);
fin.close();
dout.write(readData, 0, readData.length);
dout.flush();
/* while((i = fin.read(readData)) != -1)
{
dout.write(readData, 0, i);
}*/
//ta.appendText("\nImage Has Been Sent");
dout.flush();
fin.close();
}catch(IOException ex)
{System.out.println("Image ::"+ex);}
}
//Receiving image
if(extn.equals(".jpg") || extn.equals(".gif"))
{
//give path to new file
File file = new File(".//Downloaded"+str);
FileOutputStream fout = new FileOutputStream(file);
//receive and save image from client
byte[] readData = new byte[1024];
int offset =0;
while((i = dis.read(readData,0,readData.length-offset)) != -1){
offset += i;
}
fout.write(readData, 0, readData.length);
if(flag==1)
{
ta.append("Image Has Been Downloaded");
flag=0;
}
fout.flush();
fout.close();
}
}
Assuming that you would have to provide file name and then press download button. So on server side convert the image into byte stream and write over the connection socket. On client side recieve bytes into buffer and then create FileOutputStream providing the directory for output. Write the recieved bytes onto the file using the outputstream created.
I am trying to send a file from client to server. Below is the code i have tried. But at times, there is a packet loss during the transfer. I am not sure where i am wrong.
SERVER SIDE CODE:
public static void ReadAndWrite(byte[] aByte, Socket clientSocket,
InputStream inputStream, String fileOutput)
throws FileNotFoundException, IOException {
int bytesRead;
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try
{
fileOutputStream = new FileOutputStream( fileOutput );
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
bytesRead = inputStream.read(aByte, 0, aByte.length);
System.out.println("The length is "+bytesRead);
int count = 0;
do {
count++;
byteArrayOutputStream.write(aByte);
bytesRead = inputStream.read(aByte);
} while (bytesRead != -1);
System.out.println("The count is "+count);
System.out.println("The length is "+byteArrayOutputStream.size());
bufferedOutputStream.write(byteArrayOutputStream.toByteArray());
bufferedOutputStream.flush();
bufferedOutputStream.close();
clientSocket.close();
}
catch(Exception ex)
{
Logger.writeLog(ex,Listen.class.getName(), LogType.EXCEPTION);
throw ex;
}
CLIENT SIDE CODE:
public void readByteArrayAndWriteToClientSocket(
Socket connectionSocket, BufferedOutputStream outToClient, String fileToSend ) throws Exception
{
try{
if (outToClient != null)
{
File myFile = new File(fileToSend);
System.out.println(myFile.length());
byte[] byteArray = new byte[(int) myFile.length()];
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(myFile);
} catch (IOException ex) {
Logger.writeLog(ex, FileUtility.class.getName(), LogType.EXCEPTION);
throw ex;
}
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
try {
bufferedInputStream.read(byteArray, 0, byteArray.length);
outToClient.write(byteArray, 0, byteArray.length);
outToClient.flush();
outToClient.close();
connectionSocket.close();
return;
} catch (IOException ex) {
Logger.writeLog(ex, FileUtility.class.getName(), LogType.EXCEPTION);
throw ex;
}
}
}catch (Exception e) {
Logger.writeLog(e, getClass().getName(), LogType.EXCEPTION);
throw e;
}
}
There is no 'packet loss', just bugs in your code.
The canonical way to copy a stream in Java is as follows:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
If you know the number of bytes in advance and the sender must keep the connection open after the transfer, it becomes:
while (total < expected && (count = in.read(buffer, 0, expected-total > buffer.length ? buffer.length : (int)(expected-total))) > 0)
{
out.write(buffer, 0, count);
total += count;
}
Forget all the ByteArrayInput/OutputStreams and the extra copies. Just read from the file and send to the socket, or read from the socket and write to the file.
The sockets read method will return when its has obtained all the bytes you asked for, OR, when it stops receiving data from the network.
As transmission is often interrupted in any real network you need to keep issuing read calls until you have the number of bytes you want.
You need code something like this:
char [] buffer = new char[1024];
int expect = 1000;
int sofar = 0;
int chars_read;
try
{
while((chars_read = from_server.read(buffer[sofar])) != -1)
{
sofar = sofar + chars_read;
if (sofar >= expected) break;
}
}
catch(IOException e)
{
to_user.println(e);
}
I am developing an Android App to send a file via bluetooth to a java server using the BlueCove library version 2.1.0 based on this snippet. At the beginning everything looks fine, but the file will not transfered completly. Only about 7KB of 35KB.
Android
private void sendFileViaBluetooth(byte[] data){
OutputStream outStream = null;
BluetoothDevice device = btAdapter.getRemoteDevice(address);
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
btSocket.connect();
try {
outStream = btSocket.getOutputStream();
outStream.write( data );
outStream.write("end of file".getBytes());
outStream.flush();
} catch (IOException e) {
} finally{
try {
outStream.close();
btSocket.close();
device = null;
} catch (IOException e) {
}
}
}
PC Server
InputStream inStream = connection.openInputStream();
byte[] buffer = new byte[1024];
File f = new File("d:\\temp.jpg");
FileOutputStream fos = new FileOutputStream (f);
InputStream bis = new BufferedInputStream(inStream);
int bytes = 0;
boolean eof = false;
while (!eof) {
bytes = bis.read(buffer);
if (bytes > 0){
int offset = bytes - 11;
byte[] eofByte = new byte[11];
eofByte = Arrays.copyOfRange(buffer, offset, bytes);
String message = new String(eofByte, 0, 11);
if(message.equals("end of file")) {
eof = true;
} else {
fos.write (buffer, 0, bytes);
}
}
}
fos.close();
connection.close();
I tried already to split the byte array before writing:
public static byte[][] divideArray(byte[] source, int chunksize) {
byte[][] ret = new byte[(int)Math.ceil(source.length / (double)chunksize)][chunksize];
int start = 0;
for(int i = 0; i < ret.length; i++) {
ret[i] = Arrays.copyOfRange(source,start, start + chunksize);
start += chunksize ;
}
return ret;
}
private void sendFileViaBluetooth(byte[] data){
[...]
byte[][] chunks = divideArray(data, 1024);
for (int i = 0; i < (int)Math.ceil(data.length / 1024.0); i += 1) {
outStream.write( chunks[i][1024] );
}
outStream.write("end of file".getBytes());
outStream.flush();
[...]
}
Every help or ideas are appreciated.
You don't need any of this. The canonical way to copy a stream in Java is this:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
out.close();
Same at both ends. TCP/IP will do all the chunking for you. All you need to do is cope correctly with varying size reads, which this code does.
I have a server and client connection using sockets to transfer files, but if I want to be able to send strings to the server from the client upon user JButton actions, it throws socket closed errors (Because I used dos.close() in the Sender() constructor). The problem is, if I don't use dos.close(), the client program won't run/init the UI frame. What am I doing wrong? I need to be able to send files when the program first runs then send data later.
Sender:
public Sender(Socket socket) {
List<File> files = new ArrayList<File>();
files.add(new File(Directory.getDataPath("default.docx")));
files.add(new File(Directory.getDataPath("database.db")));
try {
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(files.size());
for (File file : files) {
dos.writeLong(file.length());
dos.writeUTF(file.getName());
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(); // If this is disabled, the program won't work.
} catch (Exception e) {
e.printStackTrace();
}
}
Downloader:
public static byte[] document;
public Downloader(Socket socket) {
try {
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
DataInputStream dis = new DataInputStream(bis);
int filesCount = dis.readInt();
for (int i = 0; i < filesCount; i++) {
long size = dis.readLong();
String fileName = dis.readUTF();
if (fileName.equals("database.db")) {
List<String> data = new ArrayList<String>();
BufferedReader reader = new BufferedReader(new InputStreamReader(bis));
String line;
while ((line = reader.readLine()) != null) {
if (line.trim().length() > 0) {
data.add(line);
}
}
reader.close();
parse(data);
} else if (fileName.equals("default.docx")) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (int x = 0; x < size; x++) {
bos.write(bis.read());
}
bos.close();
document = bos.toByteArray();
}
}
//dis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Your first receive loop in the client terminates at EOS, which only happens when you close the socket in the sender, which you don't want to do. You're sending the length ahead of the file in each case so the receiving code should look like this in both cases:
long total = 0;
while ((total < size && (count = in.read(buffer, 0, size-total > buffer.length ? buffer.length : (int)(size-total))) > 0)
{
total += count;
out.write(buffer, 0, count);
}
out.close();
That loop reads exactly size bytes from the socket input stream and writes it to the OutputStream out, whatever out happens to be: in the first case, a FileOutputStream, in the second, a ByteArrayOutputStream.