简体   繁体   中英

Data loss when sending file via java socket to an Android device

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 file as 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!

这是我的错误,当应用程序进入暂停状态时,我没有正确关闭线程,因此在恢复时创建了一个新的读取线程,因此未按预期处理数据!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM