I have to send a dynamic buffer size to the socket stream.
It works correctly, but when I try to send multiple buffers with a size
bigger than
int my_buffer_size =18 * 1024; (this is an indicative value)
I get the error (for some write):
Java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
My code is very simple:
For example If I want to send a big file I read a file stream with
byte[] bs = new byte[my_buffer_size];
while (... ){
fileInputStream.read(bs);
byte[] myBufferToSend = new byte[sizeBuffer];
DataOutputStream out = new DataOutputStream(cclient.getoutputStream());
out.writeInt(myBufferToSend.length);
out.write(myBufferToSend);
out.flush();
}
(The file is just a test the buffer size can be variable)
the SendBufferSize is 146988.
Is there a way to fix the broken pipe error? I read around but actually I didn’t solve the problem.
Thank you
any help is appreciated
I use the classic ServerSocket serverSocket;
and Socket cclient
'Broken pipe' means that you've written data to a connection that has already been closed by the other end.
Ergo the problem lies at the other end, not in this code. Possibly the other end doesn't really understand your length-word protocol for example, or doesn't implement it correctly.
If it's anything like this code it won't, because you're ignoring the result returned by read() and assuming that it fills the buffer. It isn't specified to do that, only to transfer at least one byte.
In common, receiving huge blocks is not supported by DataInputStream, because the readmethod just delegates to the underlying socket input stream and that socket input stream does not complain about not having read all. E.g. in Oracle Java 8 you get some 2^16 bytes and the rest is ignored. So when you close the socket after DataInputStream.read has returned, the sender node observes a "pipe broken" while still trying the send the rest of the huge block. Solution is a windowed read. Below is a DataInputStream-subclass, which does precisely this.
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
public class HugeDataInputStream extends DataInputStream
{
int maxBlockLength;
public HugeDataInputStream(InputStream in)
{
this(in, 0x8000);
}
public HugeDataInputStream(InputStream in, int maxBlockLength)
{
super(in);
this.maxBlockLength = maxBlockLength;
}
public int readHuge(byte[] block) throws IOException
{
int n = block.length;
if (n > maxBlockLength)
{
int cr = 0;
while (cr < n)
{
cr += super.read(block, cr, Math.min(n - cr, maxBlockLength));
}
return cr;
}
else
{
return super.read(block);
}
}
}
Related
This question already has answers here:
java.io.EOFException when try to read from a socket
(4 answers)
Closed 2 years ago.
try {
socket = new Socket("localhost", 9999);
while(true) {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
byte[] buf = new byte[1024];
FileOutputStream fout = new FileOutputStream("c:/hyebin/hyebin/excercise.jpg");
while((ois.read(buf, 0, buf.length))!=-1){
fout.write(buf, 0, buf.length);
}
System.out.println("파일 수신 및 저장 성공");
}
} catch (Exception ex) {
ex.printStackTrace();
}
java.io.EOFException
at java.base/java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2890)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3385)
at java.base/java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:942)
at java.base/java.io.ObjectInputStream.<init>(ObjectInputStream.java:385)
at comm/comm.client.main(client.java:14)
This is my client code. The first code runs normally. However, such an error occurs from the second time it is saved. I don't know where the error occurs.
This code is all sorts of problematic.
The while(true) is just bizarre, and causes the exception you see.
ObjectInputStream is used, but for absolutely no reason. plain jane inputstreams have the read() function. Don't wrap your socket in the ObjectInputStream.
ois.read does not read the full buffer. It reads at least 1 byte, and probably more, possibly the entire buffer, but it doesn't have to. You ignore how many bytes it did read, and then write the full buffer to the file, which means that if for example the network packet size is smaller than the file size, your code breaks. you need to save the value returned by the read call, if it is -1, stop, if it is not, write that many bytes (provide that value instead of buf.length as third arg to the write method
Your exception handling is deplorable. On failure, this code prints and continues.
The error is in line 14 - see the client.java:14 bit in your stack trace? That's useful information.
Resources must be guarded: You MUST close resources, and you must do so even if your code exits via exception or otherwise. There is a construct for this, called the ARM construct (automatic resource management), also called try-with.
inputstreams have a method these days to ask them to just dump themselves into a file.
Combining it all:
private static final String OUT_FILE = "c:/hyebin/hyebin.exercise.jpg";
public static void main(String[] args) throws Exception {
Socket socket = new Socket("localhost", 9999);
try (
InputStream in = socket.getInputStream();
FileOutputStream out = new FileOutputStream(OUT_FILE)) {
in.transferTo(out);
}
System.out.println("파일 수신 및 저장 성공");
}
easy, isn't it? It's generally a good idea to look at the javadoc of stuff you're using to figure out how to use it, and to find any useful shortcuts, such as the transferTo method.
Following scenario that explains my problem.
I've a PLC that acts as a server socket program. I've written a Client Java program to communicate through socket communication with the PLC.
Steps that take place in this process are:
1) For each second my Client program happen to communicate with the PLC, read the data in stream, store the data temporarily in a ByteArrayOutputStream and closing both input stream and socket. Following snippet gives the idea
try {
socket = new Socket(host, port);
is = socket.getInputStream();
outputBuffer = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int read;
if((read = is.read(buffer)) != -1) {
outputBuffer.write(buffer, 0, read);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
System.out.println("Before closing the socket");
try {
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("After closing the socket");
} catch (Exception e) {
e.printStackTrace();
}
}
2) Processing stored data according to my requirement is what I'm trying to do. So for every 1 second, client program connects to Server, read the data(if data is present), store the data, close socket and process it. And it has to happen for a very long run, probably till the Server program is on. And that may happen till for every few weeks.
3) Problem what I'm facing is, I'm able to run the above show for 1-2 hours, but from then, Client Program unable to fetch the data from the Server Program(PLC in this case), though both are connected through socket. I.e 128 bytes of data present, but Client program isn't able to read that data. And this started happening after program run successfully for almost 2hours
4) Please find the brief code which may help for you to look into.
public class LoggingApplication {
public static void main(String[] args) throws NumberFormatException {
if (args.length > 0 && args.length == 2) {
String ipAddress = mappingService.getIpAddress();
int portNo = (int) mappingService.getPortNo();
ScheduledExecutorService execService = Executors.newScheduledThreadPool(1);
execService.schedule(new MyTask(execService, ipAddress, portNo, mappingService), 1000, TimeUnit.MILLISECONDS);
} else {
throw new IllegalArgumentException("Please pass IPAddress and port no as arguments");
}
}
}
Runnable Code:
public class MyTask implements Runnable {
public ScheduledExecutorService execService;
private String ipAddress;
private int portNo;
private ConfigurationMappingService mappingService;
private MySocketSocketUtil mySocketSocketUtil;
public MyTask(ScheduledExecutorService execService, String ipAddress, int portNo, ConfigurationMappingService mappingService) {
this.execService = execService;
this.ipAddress = ipAddress;
this.portNo = portNo;
this.mappingService = mappingService;
}
public void run() {
MySocketSocketUtil mySocketSocketUtil = new MySocketSocketUtil(ipAddress, portNo);
execService.schedule(new MyTask(execService, ipAddress, portNo, mappingService), 1000, TimeUnit.MILLISECONDS);
mySocketSocketUtil.getData(); //It's able to fetch the data for almost 2 hours but from then, it's just getting empty data and it's keep on giving empty data from then. and so on.
/*
*
*Some code
*/
}
}
Here's where, I'm having the problem
mySocketSocketUtil.getData(); is able to fetch the data for almost 2 hours but from then, it's just getting empty data and it's keep on giving empty data from then. and so on. It's a big question I know, And I want to understand what might have gone wrong.
Edit: I'm ignoring the condition to check end of the stream and closing a socket based on it is because, I knew I'm going to read first 1024 bytes of data only always. And So, I'm closing the socket in finally block
socket = new Socket(host, port);
if(socket != null && socket.isConnected())
It is impossible for socket to be null or socket.isConnected() to be false at this point. Don't write pointless code.
if((read = is.read(buffer)) != -1) {
outputBuffer.write(buffer, 0, read);
};
Here you are ignoring a possible end of stream. If read() returns -1 you must close the socket. It will never not return -1 again. This completely explains your 'empty data':
from then, it's just getting empty data and it's keep on giving empty data from then, and so on
And you should not create a new Socket unless you have received -1 or an exception on the previous socket.
} else {
System.err.println("Socket couldn't be connected");
}
Unreachable: see above. Don't write pointless code.
You should never disconnect from the established connection. Connect once in the LoggingApplication. Once the socket is connected keep it open. Reuse the socket on the next read.
I think there are couple of points you need to fix before getting to the solution to your problem. Please try to follow the following suggestions first:
As #EJP said this code block is not needed.
if(socket != null && socket.isConnected()) {
also you are using a byte array of length 1024 and not using while or for loop to read the data stream. Are you expecting only a block of data which will never exceed 1024 bytes?
byte[] buffer = new byte[1024];
int read;
if((read = is.read(buffer)) != -1) {
This is also not needed as it is unreachable.
} else {
System.err.println("Socket couldn't be connected");
}
Can you explain the data stream behavior you are expecting?
Last but not the least is.read(buffer) is a blocking call so if there is no data to read yet, it will hold the thread execution at that point.
Please try to answer the questions I have asked.
#KishoreKumarKorada from your description in the comment section, it seems like you are monitoring the data change on server side. Socket stream works in a read-once fashion. So,
First thing is, you need to request from server every time and the server needs to RESEND the data on every request.
Second, the way you presented is more like you are operating on byte level, which is not very good way to do that unless you have any legitimate reason to do so. The good way is to wrap the data in JSON or XML format and send it over the stream. But to reduce bandwidth consumption, you may need to operate on byte stream sometimes. You need to decide on that.
Third, for monitoring the data change, the better way is to use some timestamp to compare when the data has changed on the server side and what is the timestamp stored on the client side, if they match, data has not changed. Otherwise fetch the data from the server side and update the client side.
Fourth, when there is data available that you are not able to read, can you debug the ins.read(...) statement to see if its getting executed and the execution goes inside the if block or if statement is evaluated to false? if true then examine the read value and let me know what you have found?
Thanks.
This question already has answers here:
How do you detect a network disconnection when downloading a file in java?
(2 answers)
Closed 7 years ago.
I am here to solve an issue i am facing. I hope to get some help from the experts.
Below is a code of a simple file downloader in java. I want to detect an exception when the connection is broken in the middle of downloading a file. Now, I run the code and in the middle of downloading the file, i turn off my wifi with keyboard wifi off button. Doing this the program hangs forever without throwing any exceptions and without terminating. It seems it blocks forever. Firstly my confusion is why is exception not thrown? Secondly, in the following code you can see this line //con.setReadTimeout(2000); which is currently commented out. Removing the comment and running the program, now if connection breaks in the middle by turning off wifi then it waits for 2 seconds and then if it cannot read then it terminates without throwing exception. So, again in this case why is it just terminating and not throwing any exception? I am very puzzled by this behavior. I hope i can get some help. Thank you very much!
import java.io.FileOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.*;
public class Main {
public static void main(String[] args) {
try{
URL website = new URL("http://128f1.downloadming1.com/bollywood%20mp3/Jai%20Ho%20(2014)/06%20-%20Naacho%20Re%20-%20DownloadMing.SE.mp3");
URLConnection con = website.openConnection();
//con.setReadTimeout(2000);
ReadableByteChannel rbc = Channels.newChannel(con.getInputStream());
FileOutputStream fos = new FileOutputStream("song.mp3");
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}
catch(Exception e){
System.out.println("got here");
e.printStackTrace();
}
System.out.println("Done downloading...");
}
}
TCP connections are designed to deal with unreliable networks and packet loss. If your network connection is gone, it will not know unless you set the SO_KEEPALIVE socket option (java.net.SocketOptions has some documentation of that option).
Unfortunately, URLConnection does not allow you to set this or any other socket option. And even if it did, the keep alive interval would be very high, two hours on most operating systems. The keep alive interval can only be changed in your operating system settings, it can not be changed through Java (the SocketOptions.SO_KEEPALIVE documentation is confusing in that regard).
Altogether, you don't get an exception because the underlying network protocol is not designed to detect whether your network medium was disrupted after the initial establishment of the connection.
As you found out, setReadTimeout helps somewhat, however you have bumped into an undocumented feature of the transferFrom method. The actual implementation of that method is in sun.nio.ch.FileChannelImpl.transferFromArbitraryChannel. I am pasting the JDK 7 code here:
private long transferFromArbitraryChannel(ReadableByteChannel src,
long position, long count)
throws IOException
{
// Untrusted target: Use a newly-erased buffer
int c = (int)Math.min(count, TRANSFER_SIZE);
ByteBuffer bb = Util.getTemporaryDirectBuffer(c);
long tw = 0; // Total bytes written
long pos = position;
try {
Util.erase(bb);
while (tw < count) {
bb.limit((int)Math.min((count - tw), (long)TRANSFER_SIZE));
// ## Bug: Will block reading src if this channel
// ## is asynchronously closed
int nr = src.read(bb);
if (nr <= 0)
break;
bb.flip();
int nw = write(bb, pos);
tw += nw;
if (nw != nr)
break;
pos += nw;
bb.clear();
}
return tw;
} catch (IOException x) {
if (tw > 0)
return tw;
throw x;
} finally {
Util.releaseTemporaryDirectBuffer(bb);
}
}
As you can see in the catch block, if some data was already written to the target, it will ignore any IOException and just return the number of bytes that were written.
Recently, I wrote a simple client server program for file transfer over standard TCP sockets. The average throughput was around 2.2Mbps over WiFi channel. My question is:
Is it possible to transfer a large file (say 5 GB) over multiple data IO streams so that each stream could transfer several parts of the same file in a parallel manner (different threads could be used for this purpose)? These file parts could be re-assembled at the receiving end.
I tried to split a small file and transfered it over a dataoutputstream. The first segment works fine, but I don't know how to read a file input stream in selective manner (I also tried mark() and reset() methods for selective reading but no use)
Here is my code (for testing purpose, I have redirected the output to fileoutputstream):
public static void main(String[] args) {
// TODO Auto-generated method stub
final File myFile=new File("/home/evinish/Documents/Android/testPicture.jpg");
long N=myFile.length();
try {
FileInputStream in=new FileInputStream(myFile);
FileOutputStream f0=new FileOutputStream("/home/evinish/Documents/Android/File1.jpg");
FileOutputStream f1=new FileOutputStream("/home/evinish/Documents/Android/File2.jpg");
FileOutputStream f2=new FileOutputStream("/home/evinish/Documents/Android/File3.jpg");
byte[] buffer=new byte[4096];
int i=1, noofbytes;
long acc=0;
while(acc<=(N/3)) {
noofbytes=in.read(buffer, 0, 4096);
f0.write(buffer, 0, noofbytes);
acc=i*noofbytes;
i++;
}
f0.close();
I got the first segment of my file (this can be copied to a DataOutputStream in one thread). Can any one suggest, how to read remaining part of the file (after N/3 byte) in a segment of N/3 so that three streams could be used in three threads for concurrent operation?
Here is the code to merge file segments at receiver end:
package com.mergefilespackage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class MergeFiles {
/**
* #param args
*/
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
IOCopier.joinFiles(new File("/home/evinish/Documents/Android/File1.jpg"), new File[] {
new File("/home/evinish/Documents/Android/File2.jpg"), new File("/home/evinish/Documents/Android/File3.jpg")});
}
}
class IOCopier {
public static void joinFiles(File destination, File[] sources)
throws IOException {
OutputStream output = null;
try {
output = createAppendableStream(destination);
for (File source : sources) {
appendFile(output, source);
}
} finally {
IOUtils.closeQuietly(output);
}
}
private static BufferedOutputStream createAppendableStream(File destination)
throws FileNotFoundException {
return new BufferedOutputStream(new FileOutputStream(destination, true));
}
private static void appendFile(OutputStream output, File source)
throws IOException {
InputStream input = null;
try {
input = new BufferedInputStream(new FileInputStream(source));
IOUtils.copy(input, output);
} finally {
IOUtils.closeQuietly(input);
}
}
}
class IOUtils {
private static final int BUFFER_SIZE = 1024 * 4;
public static long copy(InputStream input, OutputStream output)
throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
long count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
public static void closeQuietly(Closeable output) {
try {
if (output != null) {
output.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
Any help would be highly appreciated! Thanks in advance!
You can't get any more speed over the same link with more sockets. Each socket sends a certain number of packets, each of a certain size. As we double the number of sockets, the number of packets/sec*socket is halved, and then decreased even more due to collisions, overhead, and contention. Packets start to bump, jumble, and otherwise panic. The OS cannot handle the pandemonium of lost ACKs, and the WiFi card struggles to transmit at such a rate. It is losing its low-level acks as well. As packets get lost, a desperate TCP stack dials down the transmit rate. If this were to be able to come up due to signal improvement, it's now stuck at the lower speed due to silly window syndrome or another form of TCP deadlock.
Any attempt of WiFi to get any higher speeds out of wider carrier bands, MiMo, or multiple paths, has already been realized as gains, even with one socket. You can't take it any farther.
Now, wait. We're quite below WiFi speed, aren't we? Of course, we need to use buffering!
Make sure you create BufferedWriter and BufferedReader objects from your socket's getInputStream or getOutputStream methods. Then write to/read from those buffers. Your speed may increase somewhat.
You could get the byte array of the FileInputStream and split it every 10 KB (every 10.000 bytes).
Then send these parts through the streams in order.
On the server you can put the arrays together again and read the file from this giant byte array.
I have run into an interesting issue trying to upgrade one of my applications from the Java 6 to Java 7. It is a simple Java socket program. It sends a command to a COM socket and receives a response. It works perfectly in a Java 6 environment, but when I try to run the same code in a Java 7 environment, the socket appears to receive nothing in the InputStream.
I can confirm that the COM socket it's connecting to does receive the command and sends the response. This is run on the exact same machine in both cases with the firewall disabled, and it's the exact same code ran both times.
Has something changed in Java 7, do I have some deeper flaw, or is this simply a Java bug?
Here is a slightly stripped version of the code.
public static void main(String[] arguments) throws Exception {
InetAddress server = InetAddress.getByName(serverAddress);
Socket sock = SSLSocketFactory.getDefault().createSocket(server.getHostAddress(), port);
InputStream in = sock.getInputStream();
OutputStream out = sock.getOutputStream();
out.write(command.getBytes()); //Is valid command
String token = "";
responseReader: while (true) {
try {
Thread.sleep(1);
}
catch (InterruptedException exception) {}
byte[] d = new byte[in.available()];
int avail = in.read(d);
for (int i = 0; i < avail; i++) {
if (d[i] == fieldSeperator) {
token = "";
}
else if (d[i] == commandSeperator) {
break responseReader;
}
else {
token += (char) d[i];
}
}
}
}
I've tried as much as I can think of, most of the time knowing it shouldn't matter. Using different methods of reading the stream, casting to SSLSocket and making different calls, adding some sleeps.
The code is wrong. You shouldn't use available() like that. If there is no data available you will allocate a zero length buffer and execute a zero length read, which will retun zero without blocking. Use a constant like 8192 for the buffer size, and allocate the buffer outside the loop. And get rid of the sleep() too.
There are few if any correct uses of available(), and this isn't one of them.
And note that available() always returns zero for an SSLSocket, and has always done so right back to Java 1.3 and the separate JSSE download. So I am unable to accept that the same code worked in Java 6.