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.
Related
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 just realized that DataInputStream and DataOutputStream in writing reading socket
could be used to differentiate the input that was coming over.
Check this code:
Server Side. (receiving string or file)
Socket bSock = serverSocket.accept();
DataInputStream inp = new DataInputStream(bSock.getInputStream());
int iCode = inp.readInt();
switch (iCode) {
case Request.STATE_FILESHARING:
byte bp[] = new byte[iCode];
FileOutputStream fos = new FileOutputStream("s.pdf");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = inp.read(bp, 0, bp.length);
bos.write(bp, 0, bytesRead);
bos.close();
break;
case Request.STATE_CONVERSATION:
requestFound = new Request(inp.readUTF());
sendToUI(requestFound);
break;
}
Client Side. (sending string or file)
Socket socket = new Socket(myServerAddress, SocketServerPORT);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
if (isThisFileMode()) {
File myFile = new File(sLocationFile);
byte[] mybytearray = new byte[(int) myFile.length()];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray, 0, mybytearray.length);
out.writeInt(Request.STATE_FILESHARING);
out.write(mybytearray, 0, mybytearray.length);
out.flush();
} else {
out.writeInt(Request.STATE_CONVERSATION);
out.write(obReq.toString().getBytes());
out.flush();
}
But I ended up with Error. System crashed!
Anything that I forgot to add?
You're using readUTF() but not writeUTF(). Nearly all the methods of DataInputStream and DataOutputStream are symmetrical: if you call readXXX() you must call writeXXX() at the other end.
You're making the usual mistake of assuming that read() fills the buffer. It is only contracted to transfer at least one byte. You must loop:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
You need to close the socket at both server and client.
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 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.
I'm trying to implement basic communication through sockets, what I have now is:
server start's to listen on socket,
this.serverSocket_ = new ServerSocket(this.serverPort_);
clientSocket = this.serverSocket_.accept();
client connects, and server starts separate thread to operate with that client,
both open Object output and input streams,
out = new ObjectOutputStream(clientSocket_.getOutputStream());
out.flush();
in = new ObjectInputStream(clientSocket_.getInputStream());
client sends two i Doubles, String and Long over that stream (flushes after each one),
out.writeObject(conf_);
out.flush();
out.writeObject(supp_);
out.flush();
out.writeObject(separator_);
out.flush();
out.writeObject(new Long(dataFile_.length()));
out.flush();
server succesfully receives those objects over previously opened streams,
conf_ = (Double) in_.readObject();
supp_ = (Double) in_.readObject();
separator_ = (String) in_.readObject();
fileSize_ = (Long) in_.readObject();
and now "the hard part",
clients wants to send a file so opens different output stream (not object output stream) and sends the file,
FileInputStream fis = new FileInputStream(dataFile_);
BufferedInputStream bis = new BufferedInputStream(fis);
OutputStream os = clientSocket_.getOutputStream();
while (current < fileSize) {
bytesRead = bis.read(mybytearray, 0, mybytearray.length);
if (bytesRead >= 0) {
os.write(mybytearray, 0, mybytearray.length);
current += bytesRead;
}
progressBar_.setValue(current);
progressBar_.repaint();
}
os.flush();
the server receives the file (also uses simple input stream instead ObjectInputStream),
int bytesRead;
int current = 0;
tmpFile_ = File.createTempFile("BasketAnalysis", "rec.dat");
byte[] mybytearray = new byte[fileSize];
InputStream is = clientSocket_.getInputStream();
FileOutputStream fos = new FileOutputStream(tmpFile_);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(mybytearray, 0, mybytearray.length);
current = bytesRead;
do {
bytesRead = is.read(mybytearray, current,
(mybytearray.length - current));
if (bytesRead >= 0)
current += bytesRead;
} while ((bytesRead > -1) && (current < fileSize));
bos.write(mybytearray, 0, current);
bos.flush();
bos.close();
so far everything works fine, file is received, but now server performs some time consuming processing on that file after which sends response with whe results to client,
String resp = new String("Some processing result...");
out_.writeObject(resp);
out_.flush();
the client is supposed to receive the result what finishes the whole communication,
String message = (String) in.readObject();
Console.info("server > " + message);
Unfortunately, that last step on client side fails with exception:
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at basketAnalysis.client.Client.run(Client.java:74)
at java.lang.Thread.run(Unknown Source)
I want client to block on waiting for server response after sending the file, but it suddenly finishes with the exception after sending the file. I am pretty sure that I do something wrong with switching between simple streams and Object streams.
Does anybody know what should I change to haave it working?
Thank you in advance!
I think your basic misunderstanding is here:
clients wants to send a file so opens different output stream
OutputStream os = clientSocket_.getOutputStream();
That doesn't open a different output stream - that will get another reference to the same output stream which you've already got wrapped in the ObjectOutputStream. If you want two streams of data, you'll need to open two separate connections.