So, I have a piece of code which connects to a Server and downloads about 2gb of content in 2mb chunks. All this is done in a Thread. Sometimes I need to stop the Thread because different errors occured in the main Thread or I want to close the application. My problem is that I am not able to close the InputStream of the connection. Everytime I invoke the close() method the InputStream consumes the whole 2gb send by the server.
Is there a way to close an InputStream without consuming the whole content send over by the Server?
fos.getChannel().transferFrom(Channels.newChannel(res.getEntity().getContent()), bytes_read, CHUNK_SIZE);
res.getEntity().getContent().close();
res.getEntity().getContent()returns the InputStream created from the connection.
res is an apache httpResponse.
fos is the FileOutputStream I want to save the response content to.
Edit: Run method of thread
CHUNK_SIZE: int: 2mb in bytes
#Override
public void run() {
int expectedCode;
do{
try {
client = HttpClients.createDefault();
HttpGet req = new HttpGet(url.toString());
HttpResponse res = client.execute(req);
if (res.getStatusLine().getStatusCode() == 200) {
while(running){
fos.getChannel().transferFrom(Channels.newChannel(res.getEntity().getContent()), bytes_read, CHUNK_SIZE);
}
} else {
log.error(Languages.getString("Download.2") + expectedCode); //$NON-NLS-1$
}
} catch (Exception ex) {
log.error(ex);
} finally{
try{
rbc.close();
} catch(Exception ex){
log.error(ex);
}
}
}while(!isFinished() && running);
try{
rbc.close();
fos.close();
client.close();
} catch(Exception ex){
log.error(ex);
}
}
The underlying implementation of Apache HttpClient uses a ContentLengthInputStream for keeping the response. As mentioned in ContentLengthInputStream, the .close() method never actually close the stream, but read all remaining bytes until Content-Length is reached.
Solution: Instead of calling res.getEntity().getContent().close(), try res.close() or req.abort()
Related
I want to send an object from my client to my localhost server to add to database, and send result back whether the object was sent successfully or not. The object was sent successfully, but my server doesn't send the result back to client, and causes my client frame form hanged due to waiting for response from server. I don't know what's wrong with my code. Can you tell me some ways to fix this?
Here is the function to send the result:
public void sendResult(String result) {
try {
Socket clientSocket = myServer.accept();
System.out.println("Connected to client");
ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
os.writeObject(result);
System.out.println("Result sent");
} catch (Exception ex) {
ex.printStackTrace();
}
}
Where the send result function is called:
public void service() {
try {
if (receiveStudent() != null) {
Student std = receiveStudent();
if (dao.addStudent(std)) {
System.out.println("OK");
sendResult("OK");
} else {
System.out.println("FAILED");
sendResult("FAILED");
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
In addition, in the Service function, the console printed "OK", which means the if condition was satisfied.
receive student method:
public Student receiveStudent() {
Student s = new Student();
try {
Socket clientSocket = myServer.accept();
System.out.println("Connect to client successfully");
ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());
Object o = ois.readObject();
if (o instanceof Student) {
s = (Student) o;
return s;
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
Because of myServer.accept() in sendResult(), the server is again waiting for an incoming client connection while this already happened in receiveStudent(). Reuse that connection.
Share the client socket you've obtained in receiveStudent() by, e.g., turning it into a field.
public Student receiveStudent() {
...
try {
clientSocket = myServer.accept();
...
} catch (Exception ex) {
...
}
...
}
and then reuse that socket in sendResult() to send the result to the client.
public static void sendResult(String result) {
try {
...
ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
...
} catch (Exception ex) {
...
}
}
If you want to send a String as object why don't you just use something like this:
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); //for sending String messages
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); //for getting String messages
... and then when you need to send you do it like this:
out.println(textToServer"); // send to server - don't forget LN in println.
out.flush(); // to clean buffer
It should do what you need to be done.
And make sure that your client class is waiting to get that InputStream you're sending, don't forget that, since maybe it's the problem in the Client side.
Maybe Client is not accepting that incoming Socket regardless if it's ObjectInputStream or BufferedReader that will accept the incoming socket object.
You could provide us a Client class so we can see if there's missing acceptance of incoming socket.
At the end of the method make sure you close your streams and sockets.
out.close();
in.close();
socket.close();
For more details check this, this and this. I hope I was helpful :)
You're calling accept() twice. This is meaningless. You need to:
Accept the connection. This returns a Socket.
Read the request and create the response.
Send the response, via the same Socket you accepted at (1).
You also want to create a new thread per accepted socket, and you also want to do all I/O in that thread, including creating the ObjectInputStream and ObjectOutputStream. Otherwise your server isn't properly multi-threaded and multi-client.
I am making an android application that should send and receive some json files through a wifi direct connection (whenever another device is connected, they both trade all their json files).
This question is mostly about what would be the best practice, since I am fairly new both to android and java.
When a wifi direct connection is established one of the two devices (the group owner) becomes the server and opens a server socket; the other connects to said socket and sends one single json file to the server.
I want the client to send all his json files and then receive all the json files from the server, and I'm wondering how it should be done: how do I tell one file is over? Should I send the lenght of the file ahead, or make the client wait for an acknowledgement for when the server is done reading?
Can I signal "End of Data" (by closing the OutputStream?) to stop the reading loop on the receiving end and then start sending another file?
To have some context, this is currently the code I'm using:
Client side
#Override
protected String doInBackground(Void... params) {
Socket socket = new Socket();
try {
Log.d(TAG, "Opening client socket - ");
socket.bind(null);
socket.connect((new InetSocketAddress(mHost, Constants.PORT)), SOCKET_TIMEOUT);
Log.d(TAG, "Client socket - " + socket.isConnected());
OutputStream stream = socket.getOutputStream();
//There is only one file, so the loop here runs only once
File dir = Utils.graffitiDir(context);
for (File tmp : dir.listFiles()) {
FileInputStream in = new FileInputStream(tmp);
Utils.copyFileInOut(in, stream);
}
Log.d(TAG, "Client: Data written");
return "ok";
} catch (IOException e) {
Log.e(TAG, e.getMessage());
return null;
}
finally {
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
// Give up
e.printStackTrace();
}
}
}
}
}
Server side
#Override
protected String doInBackground(Void... params) {
try {
ServerSocket serverSocket = new ServerSocket(Constants.PORT);
byte buf[] = new byte[4];
String res;
Log.d(TAG, "Server: Socket opened");
Socket client = serverSocket.accept();
Log.d(TAG, "Server: connection done");
File f = new File(context.getFilesDir(), Constants.DIRECTORY);
File dirs = new File(f.getParent());
if (!dirs.exists())
dirs.mkdirs();
f.createNewFile();
File newf = new File(f, Calendar.getInstance().getTime().toString());
Log.d(TAG, "server: copying files " + f.toString());
InputStream inputstream = client.getInputStream();
//copyFile(inputstream);
Utils.copyFileInOut(inputstream, new FileOutputStream(newf));
serverSocket.close();
return newf.getAbsolutePath();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
return null;
}
}
The copyFileInOut function:
public static boolean copyFileInOut(InputStream inputStream, OutputStream out) {
byte buf[] = new byte[1024];
int len;
long startTime=System.currentTimeMillis();
try {
while ((len = inputStream.read(buf)) != -1) {
out.write(buf, 0, len);
Log.d("copyfile", "I'm writing");
}
out.close();
inputStream.close();
long endTime=System.currentTimeMillis()-startTime;
Log.d("copyfile", "Time taken to transfer all bytes is : " + endTime);
} catch (IOException e) {
Log.d(TAG, e.toString());
return false;
}
return true;
}
As a sidenote, I've seen a couple of similar questions (Sending and receiving files on socket) where the answer suggested to send the length of the file ahead, but I feel like my situation is a bit different, and I don't have the necessary experience to find out what is the best solution. I apologize if this is an obvious question, but I couldn't find an answer by myself.
In your case you should
1. send the number of files you are going to send first,
2. then send length of a file and that file. repeat for all files.
after this the server can also use the same order of sending number of files, the size of a file, that file repeat for all files.
I had to implement a Client-Server application in Java that automatically updates txt files in a Server directory depending on changes in the files in the Client side, for a homework assignment (had to, because I'm past the deadline).
I have a package that handles the changes in the files correctly, but I'm stumped about how to handle the changes in multiple files. My approach was using separate threads for each file in the client directory and using corresponding threads in the server directory for the same cause. This approach works for a single file, but not for multiples.
The code below is on the client side and calls a file's thread's checkfilestate method to handle the updates.
while(true){
for (Map.Entry<String, SynchronisedFile> entry : fileList.entrySet()) {
try {
System.err.println("SyncTest: calling fromFile.CheckFileState()");
sstt.start();
entry.getValue().CheckFileState();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
}
And on the server side, if I start a single thread using:
Thread sstt = new Thread(new SyncThreadServer(sfileList.entrySet().iterator().next().getValue(),clientSocket));
sstt.start();
It works as expected. But if I start the serverside threads at the same time (which contains methods for decoding the Json messages from the input stream) using:
for (Map.Entry<String, SynchronisedFile> entry : sfileList.entrySet())
{
Thread sstt = new Thread(new SyncThreadServer(entry.getValue(),clientSocket));
sstt.setName(entry.getKey());
}
Threads of other files start reading JSON messages intended for other threads from the input stream. I'd like to be able to stop the serverside loop from starting the next thread, at least until the checkFile method is complete for one file/thread. But I still might run into problems after the initial stage, when all the treads are running at the same time. Any solutions on how to handle multiple threads in this case? (All threads use a single socket).
Edit: As I understand, this has to do with synchronization. Threads of other files on the server are accessing the Input stream before the first thread has even finished processing the inputs meant for it. This is the code of the server thread below. I need to somehow block the other threads from accessing the input stream before the first one has finished using it. Any help would be much appreciated. Thanks.
public class SyncThreadServer implements Runnable {
SynchronisedFile toFile; // this would be on the Server //Is an instance of the syncfile class, should be able to proc insts
Socket clientSocket;
public SyncThreadServer(SynchronisedFile tf, Socket aClientSocket){
toFile=tf;
clientSocket = aClientSocket;
}
#Override
public void run() {
Instruction inst = null;
InstructionFactory instFact=new InstructionFactory();
while(true){
{
try{
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
String smsg = in.readUTF();
Instruction receivedInst = instFact.FromJSON(smsg);
System.err.println(smsg);
// The Server processes the instruction
toFile.ProcessInstruction(receivedInst);
//if(receivedInst.Type().equals("EndUpdate")){
// out.writeUTF("NEXT"); //TODO: Change to Json
// out.flush();}
//else
//{
out.writeUTF("GO"); //TODO: Change to Json
out.flush();
}
//}
catch (IOException e) {
e.printStackTrace();
System.exit(-1); // just die at the first sign of trouble
} catch (BlockUnavailableException e) {
// The server does not have the bytes referred to by the block hash.
try {
DataOutputStream out2 = new DataOutputStream(clientSocket.getOutputStream());
DataInputStream in2 = new DataInputStream(clientSocket.getInputStream());
out2.writeUTF("NGO"); //TODO: Change to Json
out2.flush();
String msg2 = in2.readUTF();
Instruction receivedInst2 = instFact.FromJSON(msg2);
toFile.ProcessInstruction(receivedInst2);
if(receivedInst2.Type().equals("EndUpdate")){
out2.writeUTF("NEXT"); //TODO: Change to Json
out2.flush();}
else
{
out2.writeUTF("GO"); //TODO: Change to Json
out2.flush();
}
} catch (IOException e1) {
e1.printStackTrace();
System.exit(-1);
} catch (BlockUnavailableException e1) {
assert(false); // a NewBlockInstruction can never throw this exception
}
}
// } //And here
}
}
}
I am trying to send the object from applet to struts action class
using object output stream but it gives me a exception java.net.ProtocolException: Cannot write output after reading input.
I created a new instance of URLConnection to giving specific url
and tried to write object in url to send the struts action class from applet
i am calling this method on save button click of applet
public saveDesign()
{
try
{
HttpURLConnection urlConnection = getServletConnection(CallServletConnection.SAVE_DESIGN, null);
// Pragma = no-cache; should be null
if(urlConnection != null && urlConnection.getHeaderFields().get("Pragma") != null)
return false;
OutputStream outstream = urlConnection.getOutputStream();//Exception occur here
ObjectOutputStream objectoutstream = new ObjectOutputStream(outstream);
objectoutstream.writeObject("abc");
objectoutstream.flush();
objectoutstream.close();
System.out.println("vctObjectDetails is write ");
}
catch (MalformedURLException exception) {
exception.printStackTrace();
}
catch(ConnectException exception) {
exception.printStackTrace();
}
catch (IOException exception) {
exception.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
}
but it doesn't work.
Please gives me some tips if anyone knows how to handle this exception.
It all has to do with the lifecycle of an HTTP request (which is what HttpURLConnection abstracts) - once the request has been sent, you cannot modify it any further - in case you have more data to send, you just make another one.
What is happening underneath is that once you call getHeaderFields() (the response header fields), the 'HttpURLConnection' sends the request and makes the response available.
I don't know what is in 'getServletConnection()', but you could try using 'doOutput()' and not reading from the response, until you have finished writing to the request.
I'm having an issue trying to get a java server to realize an (android/java) client has closed a TCP socket connection. I figured when the client calls close() on the socket, the server would catch an IOException, but this is not the case. t_recv is a thread that receives from BufferedReader in, and t_send sends using a PrintWriter out. Closing in causes a timeout and crash, and closing out doesn't really seem to do anything. The PrintWriter is created in the contructor of the t_send thread, and BufferedReader is create in the contructor of the t_recv thread. Trying to debug this, I created blank run() methods in both threads, and the same behaviour occurs.
An interesting note: the client is an Android application, and whenever the emulator freezes and windows has to force close it, the IOException is caught in the server and the "User x.x.x.x left" message is displayed.
Client closing connection:
try {
// t_recv.in.close(); - times out and crashes
// t_send.out.close(); - appears to do nothing
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
Server waiting for client to disconnect:
for (;;)
{
try {
while ( (msg = in.readLine()) != null)
{
response = msg;
System.out.println(response);
server.broadcast(response);
}
} catch (IOException e) {
System.out.println("User '" + socket.getInetAddress().toString() + "' left");
try {
socket.close();
out.close();
in.close();
} catch (IOException e1) {
e1.printStackTrace();
System.exit(-1);
}
break;
}
}
Thanks for your time.
Assuming that in is a BufferedReader, the error is in this line:
while ( (msg = in.readLine()) == null);
That will loop for ever if in is currently at the EOF. It should be:
while ( (msg = in.readLine()) != null);
See javadoc for BufferedReader.readLine(), paying specific attention to the conditions in which it returns null.