I'm creating a server/client model to send an image file from the server to the client. There's only ONE socket involved (all data are sent through it).
The server first sends the size of the image file, then sends the file data in bytes through a BufferedOutputStream.
The client first receives the size of the file(size), creates a byte[size] imageBytes, then writes the received file data into imageBytes through a BufferedInputStream.
Seems straight forward. The trouble happens when I send file size in different ways.
Way 1: using DataOutputStream and DataInputStream to send and receive file size as int.
Way 2: using a PrintWriter to println(file size), then flush; using a BufferedReader to readLine().
Way 1 works fine. But Way 2 sends the image file incorrectly.
I wonder if this is because BufferedReader still keeps its buffer after reading, and the buffer is subsequently read by the BuffereInputStream.
Here are the codes:
Server:
package test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TestServer {
public static void main(String[] args){
try {
ServerSocket serverSocket = new ServerSocket(9090);
Socket ss = serverSocket.accept();
System.out.println("Client connected!");
File file = new File("ServerFiles/Songs/Covers/album1.jpg"); //Change this path to your own path
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
byte[] imageBytes = new byte[(int) file.length()];
bis.read(imageBytes);
bis.close();
//Way 1-------------------------------------------------------------
DataOutputStream dos = new DataOutputStream(ss.getOutputStream());
dos.writeInt((int) file.length());
System.out.println("dos wrote "+file.length());
//End Way 1---------------------------------------------------------
//Way 2-------------------------------------------------------------
// PrintWriter pw = new PrintWriter(ss.getOutputStream());
// pw.println(file.length());
// pw.flush();
// System.out.println("pw flushed!");
//End Way 2---------------------------------------------------------
BufferedOutputStream bos = new BufferedOutputStream(ss.getOutputStream());
bos.write(imageBytes);
bos.flush();
System.out.println("bos flushed!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Client:
package test;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TestClient extends JFrame{
Socket cs;
ImageIcon imageIcon;
public static void main(String[] args){
try {
Socket socket = new Socket(InetAddress.getLocalHost(), 9090);
new TestClient(socket);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public TestClient(Socket cs) throws IOException{
this.cs = cs;
init();
}
private void init() throws IOException{
imageIcon = getImageIcon();
JLabel jl = new JLabel(imageIcon);
JPanel content = (JPanel) this.getContentPane();
content.add(jl);
this.setSize(600,400);
this.setVisible(true);
}
private ImageIcon getImageIcon() throws IOException{
//Way 1-------------------------------------------------------------
DataInputStream dis = new DataInputStream(cs.getInputStream());
int size = dis.readInt();
System.out.println("size="+size);
//End Way 1---------------------------------------------------------
//Way 2-------------------------------------------------------------
// BufferedReader br = new BufferedReader(new InputStreamReader(cs.getInputStream()));
// int size = Integer.parseInt(br.readLine());
// System.out.println("size="+size); //Print size
//End Way 2---------------------------------------------------------
BufferedInputStream bis = new BufferedInputStream(cs.getInputStream());
System.out.println("bis.available()="+bis.available()); //Print bis.available()
byte[] imageBytes = new byte[size];
bis.read(imageBytes);
return new ImageIcon(imageBytes);
}
}
Outputs:
Way 1:
Server:
Client connected!
dos wrote 23215
bos flushed!
Client:
size=23215
bis.available()=23215
Way 2:
Server:
Client connected!
pw flushed!
bos flushed!
Client:
size=23215
bis.available()=6837
I'd say the difference comes from DataOutputStream writing the integer in binary format, i.e. it splits the integer into 4 bytes and writes those, whereas the PrintWriter does String.valueOf(paramInt) and thus would send the bytes of the string "23215" to the client.
Since you're already sending binary data (the image), why don't you stick to way 1? You'd normally not need the header to be human readable.
There is no contract on input streams that say you will get all the data in one read. You need to keep looping on available() until it returns a negative number. Modify your code to do this and then compare your two scenarios again.
Related
I have designed a Java Client class that is required to send a byte[] array to a Java Server class via a socket. Here is my code:
ByteArrayClient.java
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
public class ByteArrayClient {
public static void main(String[] args) {
//make POJO__________________________
ByteEncodeSubscriptionReq sr1=ByteEncodeSubscriptionReq.makeRequest(103, "Str1", "Str2");
//Connection details____________________
String serverName = "localhost";
int port = 6060;
try {
//Establish Connection with server_______________________________
System.out.println("ByteArrayClient: Connecting to " + serverName +":" + port+"...");
Socket client = new Socket(serverName, port);//make new socket
System.out.println("ByteArrayClient: connected to " + client.getRemoteSocketAddress());
//Encode POJO to ByteArray________________________________
byte[] SubscripReqByteArray=ByteEncodeSubscriptionReq.encode(sr1);
//encoded correctly to a 44 bit byte array
System.out.println("ByteArrayClient: SubscripTionRequest successfully encoded");
//Send POJO ByteArray to server__________________________
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.write(SubscripReqByteArray);;
System.out.println("ByteArrayClient: POJO sent to server");
//Receive Server response_________________________________
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
System.out.println("ByteArrayClient received: " + in.readUTF());
//close socket____________________________________
client.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("PojoClient: Connection Failed");
}
}
}
...and ByteArrayServer.java
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
public class ByteArrayServer extends Thread{
private ServerSocket serverSocket;
public ByteArrayServer(int port) throws IOException {
serverSocket = new ServerSocket(port);//create server socket
serverSocket.setSoTimeout(15000);//socket closes after 15 seconds
this.start();
}
public void run() {
while (true) {//server runs infinitely______________
try {
System.out.println("ByteArrayServer: Waiting for client on port " + serverSocket.getLocalPort() + "...");
Socket servedClient = serverSocket.accept();//client socket
System.out.println("ByteArrayServer: connected to " + servedClient.getRemoteSocketAddress());
//Receive Client ByteArray___________________________________________
ByteEncodeSubscriptionReq receivedReq=new ByteEncodeSubscriptionReq();//server side POJO
System.out.println("ByteArrayServer: created SubscriptionReq Object");
InputStream PojoStreamHolder = servedClient.getInputStream();
System.out.println("ByteArrayServer: client InputStream received");
byte[] clientByteStream=new byte[44];//same size as Pojo byte requirement
_____/*MY CODE IS STUCK SOMEWHERE HERE*/__________
servedClient.getInputStream().read(clientByteStream);
System.out.println("ByteArrayServer: clientByteStream received: "+clientByteStream[0]+" "+clientByteStream[1]);
receivedReq=ByteEncodeSubscriptionReq.decode(clientByteStream);
//Send confirmation to Client__________________________________________________
DataOutputStream out = new DataOutputStream(servedClient.getOutputStream());
if(receivedReq.getRequestSymbol().trim().length()!=0){
out.writeUTF("ByteArrayServer received Subscription ID="+receivedReq.getSubscriptionID());
System.out.println("ByteArrayServer: new SubscriptionRequest ID="+receivedReq.getSubscriptionID()+" Subscriber_Name="+receivedReq.getSubscriberName());
}else{
out.writeUTF("ByteArrayServer: did not receive Subscription ID");
}
//Close Client socket_________________________________________________________
//server.close();
//serverSocket.close();
} catch (SocketTimeoutException s) {
System.out.println("PojoServer: Socket timed out after " + getTimeElapsedInSeconds(startTime) + " seconds from start");
break;
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String[] args) {
// int port = Integer.parseInt(args[0]);//to get port as an Argument
int port = 6060;
try {
Thread t = new ByteArrayServer(port);
startTime = System.currentTimeMillis();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Here is the Server console output:
ByteArrayServer: Waiting for client on port 6060...
ByteArrayServer: connected to /127.0.0.1:64233
ByteArrayServer: created SubscriptionReq Object
ByteArrayServer: client InputStream received
The issue is that while the Stream is received by the server without errors, it gets stuck near servedClient.getInputStream().read(clientByteStream); method and does not proceed further.
I've also tried
int count=servedClient.getInputStream().read(clientByteStream);
and
DataInputStream in = new DataInputStream(servedClient.getInputStream());
long bStr=in.readLong();
and
ObjectInputStream PojoObjHolder = new ObjectInputStream(PojoStreamHolder);
byte[] clientByteStream2 = (byte[])PojoObjHolder.readObject();
..but they show the same problem as well.
How should I pass the Byte Array between the two classes without extra imports?
The problem was in my ByteArrayClient Class. I had to link the OutputStream with the client socket, rather than creating a new instance of it. So I replaced:
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.write(SubscripReqByteArray);;
with
OutputStream os = client.getOutputStream(out);
os.write(SubscripReqByteArray);;
Thank you for the hint Ekant
DataInputStream.readFully(byte[] b) will finish only when in inputstream bytes till b.length available. So for sure you need to debug if you have all the bytes or not.And the solution is to make those byte available so that the function will finish.
Same for DataInputStream.read(byte[] b) The method is blocked until input data is available.
Please make sure by debugging your app that inputstream have 44 bytes.
Try below to count available bytes and you can read those easily.
// count the available bytes form the input stream
int count = is.available();
// create buffer
byte[] bs = new byte[count];
// read data into buffer
dis.read(bs);
I would SEND " filename" and "file " through socket , I was able to easily send the file but when I try to send strings eg PrintWriter pw.println ( ) or DataOutputStream or " out.writeUTF ( ) " the file is sent corrupt, I read a lot of questions on StackOverflow but have not found the answer , I'm looking for some example to send strings and files , can you help ?
server
package serverprova;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class ServerProva {
final static int porta=8888;//porta server dove si collegano i client
public static void main(String[] args) throws IOException {
// TODO code application logic here
ServerSocket serverSocket=null;
boolean ascoltando=true;
serverSocket = new ServerSocket(porta);//avvia il server con il numero di porta
Socket s;
BufferedReader br1=null;
// ****** interfaccia f=new interfaccia);
boolean r=true;
BufferedInputStream bis=null;
Scanner sc;
FileOutputStream fout;
while(ascoltando)
{
s=serverSocket.accept();// this socket
String filename="";
String nome_cartella="";
InputStream in = null;
OutputStream out = null;
DataInputStream inString;
inString = new DataInputStream(new BufferedInputStream(s.getInputStream()));
// filename = inString.readUTF();
// nome_cartella = inString.readUTF();
in = s.getInputStream();
//out = new FileOutputStream(nome_cartella+"/"+filename);
out = new FileOutputStream("ciao"+"/"+"asd.jpg");
byte[] b = new byte[20*1024];
int i ;
while((i = in.read(b)) >0){
out.write(b, 0, i);
}
out.close();
in.close();
//inString.close();
s.close();
}
}
}
client
package clientprova;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class ClientProva {
final static int porta=8888;
public static void main(String[] args) throws FileNotFoundException, IOException {
File file;
file = new File("kirlian12.jpg");
InetAddress host = InetAddress.getLocalHost();
Socket sock = new Socket(host.getHostName(), 8888);
DataOutputStream outString = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream()));
// outString.writeUTF(file.getName());
// outString.writeUTF("rivelatore2");
// outString.flush();
byte[] b = new byte[20*1024];
InputStream in = new FileInputStream(file);
OutputStream out = sock.getOutputStream();
int i ;
while ((i = in.read(b)) >0 ) {
out.write( b , 0 , i);
}
out.close();
in.close();
sock.close();
}
}
when I try to uncomment the commented lines , my files get corrupted
When you wrap InputStream with BufferedInputStream, the latter "takes ownership" of InputStream. This means that when you call readUtf(), BufferedInputStream may read more bytes from InputStream than it is necessary for reading UTF string. So, when you next access InputStream directly, some part of transferred file is missing (because it was previously read into BufferedInputStream's buffer and currently resides there).
inString = new DataInputStream(new BufferedInputStream(s.getInputStream()));
filename = inString.readUTF();
nome_cartella = inString.readUTF();
...
in = s.getInputStream();
while((i = in.read(b)) >0){
You must choose from two alternatives: either to always use raw InputStream OR to always use BufferedInputStream. The same reasoning works also for OutputStream (but you managed to avoid problem by calling flush()).
I have send a image that is about 500kb but in the server ,the image that receive is more than 500kb.I wonder that is there any logical problems I had made? the speed of the network is about 100kb/s.
the client
package client;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class client {
public static void main(String[] args) {
Socket s = null;
BufferedOutputStream bo = null;
BufferedInputStream bi = null;
try {
s = new Socket("127.0.0.1",12349);
bo = new BufferedOutputStream(s.getOutputStream());
bi = new BufferedInputStream(new FileInputStream("1.jpg"));
byte [] bys =new byte[1024];
while((bi.read(bys))!=-1){
bo.write(bys);
}
bo.flush();
System.out.println("already post the image");
bi.close();
} catch (IOException e) {
}finally{
try {
s.close();
} catch (IOException e) {
System.out.println("close failed");
}
}
}
}
server
package server;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class sserver {
public static void main(String[] args) {
ServerSocket ss = null;
Socket s = null;
BufferedOutputStream bo = null;
BufferedInputStream bs = null;
try {
ss = new ServerSocket(12349);
s = ss.accept();
bo = new BufferedOutputStream(new FileOutputStream("2.jpg"));
bs = new BufferedInputStream(s.getInputStream());
byte [] bys =new byte[1024];
while((bs.read(bys))!=-1){
bo.write(bys);
}
bo.flush();
System.out.println("upload success");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
ss.close();
} catch (IOException e) {
System.out.println("close failed");
}
}
}
}
The problem is that you are disregarding the number of bytes read:
while((bi.read(bys))!=-1){
bo.write(bys);
}
This means that you always write 1024 bytes to bo, even if you read fewer than 1024 bytes from bi.
You need to assign the number of bytes read to a variable, and pass that to the write call:
int bytesRead;
while((bytesRead = bi.read(bys))!=-1){
bo.write(bys, 0, bytesRead);
}
Please write exacte byte which you received like below
int len= 0 ;
while( ( len = bi.read(bys))!=-1){
bo.write(bys,0, len);
}
Same code change required in both client and server side. I tested at my end and found that both file has same size afterthis change
Your server code is always writing full length of bys array into output stream.
Proper way to do it:
byte [] bys =new byte[1024];
while(true) {
int numRead = bs.read(bys);
if (numRead == -1)
break;
bo.write(bys, 0, numRead);
}
I'm trying to develop a simple Java file transfer application using TCP.
My current server code is as follows:
package tcp.ftp;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class FTPServer {
public static void main(String[] args) {
new FTPServer().go();
}
void go() {
try {
ServerSocket server = new ServerSocket(2015);
System.out.println("server is running ....!");
while (true) {
Socket socket = server.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String file = reader.readLine();
System.out.println("file to be downloaded is : " + file);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
while (true) {
int octet = bis.read();
if (octet == -1) {
break;
}
bos.write(octet);
}
bos.flush();
//bos.close();
}
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
Using my current server code above, the downlloding does not work as expected. the above code sends part of the file to the client , not the entire file. Note that I used the flush method to flush the buffer. but when I replace the flush () method by the close () method, the file is fully sent to the client whithout any loss. Could anyone please explain this behavior!
UPDATE: Here is the code of my client:
package tcp.ftp;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
*
* #author aaa
*/
public class FTPClient {
public static void main(String[] args) {
String file = "JasperReports-Ultimate-Guide-3.pdf";
try {
InetAddress address = InetAddress.getLocalHost();
Socket socket = new Socket(address, 2015);
System.out.println("connection successfully established ....!");
PrintWriter pw = new PrintWriter(socket.getOutputStream());
pw.println(file);
pw.flush();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy" + file));
while (true) {
int octet = bis.read();
if (octet == -1) {
break;
}
bos.write(octet);
}
bos.flush();
System.out.println("file download is complete ...!");
} catch (UnknownHostException ex) {
System.out.println(ex.getMessage());
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
Another behavior without the use of Socket. take the following code that copy a file from a source to a destination:
public class CopieFile {
static void fastCopy(String source, String destination) {
try {
FileInputStream fis = new FileInputStream(source);
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream(destination);
BufferedOutputStream bos = new BufferedOutputStream(fos);
while (true) {
int octet = bis.read();
if (octet == -1) {
break;
}
bos.write(octet);
}
bos.flush();
} catch (FileNotFoundException ex) {
System.out.println(ex.getMessage());
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
public static void main(String[] args) throws IOException {
String source = "...";
String destination = "...";
fastCopy(source, destination);
}// end main
}// end class
the above code to copy a file from one location to another without any loss. Note well that I did not close the stream.
If you never close the stream the client wil never get end of stream so it will never exit the read loop.
In any case the stream and the socket are about to go out of scope, so if you don't close them you have a resource leak.
I am trying to implement FTP protocol using socket programing in java. I am using the ObjectOutputStream to write the data requested to the socket in the server side but i am getting the following error on the console window..
Software caused connection abort: socket write error
Here is the implementation of my program
Server side:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class FTPServer {
public static void main(String[] args) {
try {
#SuppressWarnings("resource")
ServerSocket ss = new ServerSocket(4550);
while(true) {
Socket socket = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
FileInstance file = new FileInstance();
System.out.println(file.srcDir = br.readLine());
System.out.println(file.destDir = br.readLine());
System.out.println(file.filename = file.srcDir.substring(file.srcDir.lastIndexOf("/") + 1));
File f = new File(file.srcDir);
byte[] bytes = new byte[(int)f.length()];
FileInputStream fis = new FileInputStream(f);
fis.read(bytes);
file.FILE_SIZE = bytes.length;
file.fileData = bytes;
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(file);
System.out.println("Success");
oos.close();
fis.close();
br.close();
}
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
Client Side:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class FTPClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 4550);
BufferedReader sbr = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter the path of requested file");
String path = sbr.readLine();
System.out.println(path);
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
System.out.println("Enter Destination");
path = path + "\n" + sbr.readLine();
System.out.println(path);
pw.write(path);
pw.close();
sbr.close();
// receive file
ObjectInputStream ois= new ObjectInputStream(socket.getInputStream());
FileInstance file = (FileInstance)ois.readObject();
ois.close();
if(!new File(file.destDir).exists())
new File(file.destDir).mkdir();
File nfile = new File(file.destDir + "/" + file.filename);
FileOutputStream fos = new FileOutputStream(nfile);
fos.write(file.fileData);
fos.close();
socket.close();
System.out.println("Success");
} catch(IOException e) {
System.out.println(e.getMessage());
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
}
}
this is the FileInstance class......
import java.io.Serializable;
public class FileInstance implements Serializable {
private static final long serialVersionUID = 1L;
public String destDir;
public String srcDir;
public String filename;
public long FILE_SIZE;
public byte[] fileData;
public String status;
}
You have two problems in FTPClient
You are closing the socket prematurely. At line 22 pw.close() needs to be pw.flush()
Even after you fix the first issue the server will hang. You need to add a newline to the end of the path string you send so the server, using readLine(), can read entire lines; otherwise it waits forever for a complete line that never arrives.
This was trivial to debug in Eclipse. If you want to be a good developer, debugging skills are crucial. Set more than one breakpoint and see what happens. Experiment. Play. Learn.