0

I develop a socket-based chat application in java. I created two client, desktop client and mobile client on Android, and everything was fine with text messages, now that I added the file sending feature, I am faced with indeterminate behavior on the Android client, Sometimes it gets the whole file, sometimes it crashes on reading the file, or I use exactly the same transfer code as on the desktop client ! My client application send command in json format to the server , and the server make a reply in the same format with the result, in file request, the server reply contains 'files' filed so client should enter in MFtp.ftpGetFile method, beacause the server after sending a result with fileas field automaticaly enter in sendFile method Here is my transfer code!

MFtp.java

package com.molo.ftp;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class MFtp {
public static boolean ftpPut(File file,DataOutputStream out){
    //File file=new File(fname);
    if(!file.exists())
        return false;
    {
        System.out.println("Begin sending file");
        BufferedInputStream fin=null;
        try{
            fin= new BufferedInputStream(new FileInputStream(file));
            String fname=file.getName();
            long fileSize=file.length();
            //send file name;
            out.writeUTF(fname);
            //send file size
            out.writeLong(fileSize);
            out.flush();//send completely those informations
            int byteRead=0;
            byte[] buffer=new byte[(int) Math.min(4096, fileSize)];
            System.out.println("Buffer size: "+buffer.length);
            while((byteRead=fin.read(buffer))>0){
                out.write(buffer,0,byteRead);
                out.flush();
                System.out.println("BYTE READ AND WRITE TO SERVER :"+byteRead);
            }
            System.out.println("File totaly sent");
            out.flush();
            fin.close();
        }catch(NumberFormatException e){
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    return true;
}
 public static boolean ftpPut(String fname,DataOutputStream out){
    File file=new File(fname);
    if(!file.exists())
        return false;
     {
        System.out.println("Begin sending file");
        BufferedInputStream fin=null;
        try{
            fin= new BufferedInputStream(new FileInputStream(file));
            long fileSize=file.length();
            fname=file.getName();
            //send file name;
            out.writeUTF(fname);
            //send file size
            out.writeLong(fileSize);
            out.flush();//send completely those informations
            int byteRead=0;
            byte[] buffer=new byte[(int) Math.min(4096, fileSize)];
            System.out.println("Buffer size: "+buffer.length);
            while((byteRead=fin.read(buffer))>0){
                out.write(buffer,0,byteRead);
                out.flush();
                System.out.println("BYTE READ AND WRITE TO SERVER :"+byteRead);
            }
            System.out.println("File totaly sent");
            out.flush();
            fin.close();
        }catch(NumberFormatException e){
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    return true;
}
public static File ftpGetFile(DataInputStream din,String dir){

    //read file size from the client
    try{
        //read file name
        String fname=din.readUTF();
        //read filename
        long fileSize=din.readLong();

        File outPut=new File(dir+"/"+fname);
        BufferedOutputStream fout=null;
        fout= new BufferedOutputStream(new FileOutputStream(outPut));
        long byteRestants=fileSize;
        byte[] buffer=new byte[(int) Math.min(4096, fileSize)];
        System.out.println("Start receiving file: "+fname+" / "+fileSize);
        int byteToRead=0;
        while(byteRestants>0){
            byteToRead=din.read(buffer, 0,(int)Math.min(buffer.length, byteRestants));
            byteRestants-=byteToRead;
            fout.write(buffer,0,byteToRead);
            System.out.println("Byte restant: "+byteRestants);
        }
        fout.close();
        return outPut;
    }catch(NumberFormatException e){
        return null;
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return null;
    }   
}

}

And hier is my client read thread code where i call the MFtp getFile method:

private class ReadThread extends Thread{
    @Override
    public void run() {
        if(reader==null){
            try {
                System.out.println("Openning");
                reader=new DataInputStream(new BufferedInputStream(socket.getInputStream()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        while(go){

            try {
                String line= readLine(reader);
                if(line==null)
                    break;
                System.out.println("Client.ReadThread:line "+line);
                JSONObject result= new JSONObject(line);
                if(!result.has("hash"))
                    continue;
                Response r=new Response(result.getLong("hash"),result.getInt("status"), result.get("data"));
                //System.out.println("Result: "+result.toString());
                MediaFile[] medias=null;
                if(result.has("files")){
                    JSONArray list=result.getJSONArray("files");
                    System.out.println("Client.ReadThread:line "+"Has Media :"+list.length());
                    // List<MediaFile> files= new ArrayList<>();
                    medias=new MediaFile[list.length()];
                    for(int i =0;i<list.length();i++){
                        JSONObject obj=list.getJSONObject(i);
                        MediaFile m=new MediaFile();
                        m.name=obj.getString("name");
                        m.size=obj.getLong("size");
                        m.type=obj.getString("type");
                        Log.e("Client.medias.receiving","m.size: "+m.size+" m.name "+m.name+" m.type : "+m.type);
                        m.file= MFtp.ftpGetFile(reader, MainActivity.TEMP_DIR);
                        if(m.file!=null){
                            m.absolutPath=m.file.getAbsolutePath();
                            Log.e("Client.received: ",m.absolutPath);
                        }else{
                            Log.e("Client.received: ","Failed to save file");
                            System.out.println("Client.received: "+"Failed to save file");
                        }
                    }
                }
                r.medias=medias;
                if(queryManager!=null && r.hash>0){
                    queryManager.onResult(r);
                }
                else if(listener!=null && r.hash<=0)
                    listener.onReceiveNewMessage(r);
            }catch(SocketException e){
                if(listener!=null)
                    listener.onSocketExceptionWhenRead(socket);
            }
            catch (IOException e) {
                if(listener!=null)
                    listener.onIOExceptionWhenRead(socket);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(40);
            } catch (InterruptedException e) {
                // TODO: handle exception
                //readThread.interrupt();
                break;
            }
        }

    }
}

The reader thread is listing on socket, when it receive a new message from socket, it parse it in json format , and then creat a new Response object, but if the response contains the files field , so that means that the serveur will send a file just after that like hier in the code

...............
else if(command.matches("getUserProfil")){
    if(request.has("user")){
        String userLog=request.get("user").asText();
        ObjectNode n=mapper.createObjectNode();
        Membre m=memberManager.getOne(userLog);
        MediaFile f=new MediaFile();
        f.file=new File(m.getProfil());
        f.name=f.file.getName();
        f.size=f.file.length();
        f.type="image/png";
        n.put("cache", true);
        System.out.println("SIZE: "+f.size+" ;; "+f.size);
        println(mOut, createResponse(comId, MyStandarMessageType.OK, n,f));//will send a json string with "files" as a field
        mOut.flush();
        sendFile(f);
    }
}
...........the sendFile method.........
private void sendFile(MediaFile... files) throws IOException {
    if(files!=null && files.length >0){
        System.out.println("SendFile");
        for(MediaFile f:files){
            System.out.println("Start sending file");
            MFtp.ftpPut(f.file,mOut);
        }   
    }
}

On the desktop there is no problem, but on Android client , sometimes file is received successfully, but more times no! The most illogic is that in the client read thread, after entering in ftpGetFile method , the line String line=readLine(reader) (in readThread) is called instead of the String fname=din.readUTF() in ftpGetFile method

This is the log cat in one case, but sometimes the file is received completely

I/System.out: Client.ReadThread:line {"hash":2,"status":200,"data":{"cache":true},"files":[{"type":"image/png","size":1875,"name":"prof_molo_1492209637904.png"}]}
I/System.out: Client.ReadThread:line Has Media :1
I/System.out: Client.ReadThread:line prof_molo_1492209637904.png
I/System.out: fGetFile
I/System.out: MFt.ftpGetFile name :
I/System.out: MFt.ftpGetFile size: 122915152
W/System.err: java.io.FileNotFoundException: /storage/sdcard0/molochat/temp: open failed: EISDIR (Is a directory)
W/System.err: org.json.JSONException: Value prof_molo_1492209637904.png of type java.lang.String cannot be converted to JSONObject
W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:416)
W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:73)
W/System.err:     at com.molo.app.chat.ftp.MFtp.ftpGetFile(MFtp.java:99)
W/System.err:     at com.molo.app.chat.net.Client$ReadThread.run(Client.java:228)
W/System.err: Caused by: libcore.io.ErrnoException: open failed: EISDIR (Is a directory)
W/System.err:     at org.json.JSON.typeMismatch(JSON.java:111)
W/System.err:     at org.json.JSONObject.<init>(JSONObject.java:158)
W/System.err:     at org.json.JSONObject.<init>(JSONObject.java:171)
W/System.err:     at com.molo.app.chat.net.Client$ReadThread.run(Client.java:209)
W/System.err:     at libcore.io.Posix.open(Native Method)
W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:400)
W/System.err:   ... 4 more
E/Client.received:: Failed to save file
I/System.out: Client.received: Failed to save file

:'(

Help please!

  • You have a chat application by FTP? How would that work? – greenapps Apr 18 '17 at 20:01
  • `And hier is my client read thread code where i call the MFtp getFile method:` Yes and several times. Why not mention that? And before the client reads lines containing json. You should have started your post telling that the server sends json first. P!ease retry.. – greenapps Apr 18 '17 at 20:13
  • Please dont post images of logcat. Post text only. – greenapps Apr 18 '17 at 20:16
  • @greenapps my server listen receive command from the client in json format `{hash:...,command:..,...}`, and return a response on base of the command field . So when the client send `getUserProfil`to the server, first the server return a response like this :`{hash:..,files:[{size:fsize,name:fname,type:image/png`}]} and immediately it enter in sendFile method supposing the client after receiving the response with 'files' as a field would also enter in getFile method, the problem is that the client enter in that method, but don't read on socket in the method , instead in read in the read Thread – Mahamadou DOUMBIA Apr 18 '17 at 20:30
  • 1
    `You should have started your post telling that the server sends json first. P!ease retry..`. So start your post with it was the remark. Please remove your comment. And post the logcat. – greenapps Apr 18 '17 at 20:45
  • Ok , edition done now ! – Mahamadou DOUMBIA Apr 18 '17 at 22:51
  • `Log.e("Client.medias.receiving","m.size: "+m.size+" m.n....` Why dont we see that in the log? – greenapps Apr 18 '17 at 23:27
  • `/storage/sdcard0/molochat/temp: open failed: EISDIR (Is a directory)` Please comment on this file not found exception. Should this be a file or a directory? – greenapps Apr 18 '17 at 23:35
  • `/storage/sdcard0/molochat/temp`is normaly a directory in which file should be saved , that exception is beacause the file name is not read in the MFtp.ftpGetFile – Mahamadou DOUMBIA Apr 19 '17 at 00:10
  • `I/System.out: Client.ReadThread:line prof_molo_1492209637904.png` this is the file name normaly, should be read in MFtp.fptGetFile methode and not in ReadThread run method – Mahamadou DOUMBIA Apr 19 '17 at 00:14
  • You did not answer all my questions. – greenapps Apr 19 '17 at 07:22
  • When you tell me to remove the log image and paste it as text , i already had execute again the program with that line comented , that's why we don't see it – Mahamadou DOUMBIA Apr 19 '17 at 08:34
  • problem solved! The problem was that when i interrupt my readThread that found that the reader(`DataInputStream`) is reading on socket, so when i run the thread again , and the sever send a file , the old thread which is running read the a part of the file , and data are all mixed , so an exception is throw (JsonParseException ) – Mahamadou DOUMBIA Apr 20 '17 at 10:46

1 Answers1

0

It was my mistake, I didn't close thread correctly when the application goes in pause, so on resume a new Read Thread was created, so data were not handled as expected !