Java TCP文件传输数据随机丢失

时间:2017-07-18 19:44:58

标签: java file tcp

[编辑:此帖子已标记为重复,未经正确审核。这两个帖子解决了完全不同的问题,审稿人没有花时间仔细阅读。]

服务器将连接到三个客户端实例。服务器有三个线程来接收来自这三个客户端的请求。客户端的三个实例中的每一个都将具有ServerThread(服务器从该线程请求文件或文件列表)和UserThread(它将接受用户输入并与服务器通信并根据用户输入接收文件/文件列表)

让我们说client_0想要一个拥有client_1的文件。当client_0的UserThread向服务器请求文件时,服务器与client_1的ServerThread通信,client_1的ServerThread将文件的byteArray发送到服务器。然后,服务器将byteArray发送回client_0和client_0的UserThread,然后将byteArray保存为文件。

我使用相同类型的代码让服务器从client_1接收bytearray,并使用client_0从服务器接收byteArray。服务器的代码每次都完美地工作并且完美地接收byteArray但是在client_0中,接收byteArray的循环卡在文件的最后部分,尽管相同类型的循环正在工作完美的服务器。变量position包含已收到的byteArray的多少,并且它没有到达client_0中的FILE_SIZE,但在服务器中没有任何问题。 System.out.println()语句证实了这一点。

此外,client_0中的这个问题发生在90%的时间。在另外10%中,client_0中的循环就像它应该的那样工作!为什么会这样?

代码很长但如果有人设法通过并给出一些建议,那将是一个很大的帮助。

服务器:

package server;
import java.io.*;
import java.net.*;

public class Server {

    public static void main(String[] args) throws Exception {
        String[] id={"cp 1","cp 2","cp 3"}, pass={"123","456","789"};
        ServerSocket welcome = new ServerSocket(6000), tmpSocket;
        Socket STsocket, UTsocket;
        int startSTport = 6001;
        int startUTport = 6011;

        // for ServerThread of client
        BufferedReader STmsgFrom[] = new BufferedReader[3];
        PrintWriter STmsgTo[] = new PrintWriter[3];
        DataInputStream[] STfileFrom = new DataInputStream[3];
        // for UserThread of client
        BufferedReader UTmsgFrom[] = new BufferedReader[3];
        PrintWriter UTmsgTo[] = new PrintWriter[3];
        DataOutputStream[] UTfileTo = new DataOutputStream[3];

        for(int i=0; i<3; i++) {
            // connecting initially
            System.out.println("Waiting for client "+i);
            Socket client = welcome.accept();
            PrintWriter send = new PrintWriter(client.getOutputStream(),true);
            BufferedReader receive = new BufferedReader(new InputStreamReader(client.getInputStream()));

            // sending serial number
            send.println(Integer.toString(i));

            // sending ports for thread sockets
            send.println(Integer.toString(startSTport+i));
            send.println(Integer.toString(startUTport+i));

            // accepting sockets
            tmpSocket = new ServerSocket(startSTport+i);
            STsocket = tmpSocket.accept();
            tmpSocket = new ServerSocket(startUTport+i);
            UTsocket = tmpSocket.accept();

            // creating communications
            STmsgFrom[i] = new BufferedReader(new InputStreamReader(STsocket.getInputStream()));
            STmsgTo[i] = new PrintWriter(STsocket.getOutputStream(),true);
            STfileFrom[i] = new DataInputStream(STsocket.getInputStream());

            UTmsgFrom[i] = new BufferedReader(new InputStreamReader(UTsocket.getInputStream()));
            UTmsgTo[i] = new PrintWriter(UTsocket.getOutputStream(),true);
            UTfileTo[i] = new DataOutputStream(UTsocket.getOutputStream());

            System.out.println("Connected client "+i);
        }

        ClientThread ct0 = new ClientThread(0,STmsgFrom,STmsgTo,STfileFrom,UTmsgFrom,UTmsgTo,UTfileTo);
        ClientThread ct1 = new ClientThread(1,STmsgFrom,STmsgTo,STfileFrom,UTmsgFrom,UTmsgTo,UTfileTo);
        ClientThread ct2 = new ClientThread(2,STmsgFrom,STmsgTo,STfileFrom,UTmsgFrom,UTmsgTo,UTfileTo);
        ct0.start();
        ct1.start();
        ct2.start();

        System.out.println("Server Stup Complete!");
    }

}

class ClientThread extends Thread {
    String msg;
    int cid;
    BufferedReader[] STmsgFrom;
    PrintWriter[] STmsgTo;
    DataInputStream[] STfileFrom;

    BufferedReader[] UTmsgFrom;
    PrintWriter[] UTmsgTo;
    DataOutputStream[] UTfileTo;
    public ClientThread(int cid,BufferedReader[] STmsgFrom,PrintWriter[] STmsgTo,DataInputStream[] STfileFrom,BufferedReader[] UTmsgFrom,PrintWriter[] UTmsgTo,DataOutputStream[] UTfileTo) {
        this.cid=cid;

        this.STmsgFrom=STmsgFrom;
        this.STmsgTo=STmsgTo;
        this.STfileFrom = STfileFrom;

        this.UTmsgFrom=UTmsgFrom;
        this.UTmsgTo=UTmsgTo;
        this.UTfileTo = UTfileTo;
    }

    @Override
    public void run() {
        while(true) {
            try {
               // receiving request from receiver UserThread
                msg = UTmsgFrom[cid].readLine();
                if(msg.equals("get list")) {    // receiver requested for file list
                    System.out.println("Request from "+cid+": "+msg);
                    for(int i=0; i<3; i++) {
                        if(i==cid) continue;

                        // sending request to sender ServerThread
                        STmsgTo[i].println("give list");
                        System.out.println("Request to "+i);

                        // receive file count from sender ServerThread
                        int cnt = Integer.parseInt(STmsgFrom[i].readLine());
                        System.out.println(i+" has files: "+cnt);

                        // sending source identity to receiver UserThread
                        UTmsgTo[cid].println(Integer.toString(i));

                        // send file count back to receiver UserThread
                        UTmsgTo[cid].println(Integer.toString(cnt));

                        // get and send file names to receiver
                        for(int j=0; j<cnt; j++) {
                            msg = STmsgFrom[i].readLine();
                            UTmsgTo[cid].println(msg);
                        }
                    }
                } else if(msg.equals("get file")) {
                    // get source id and filename
                    int source = Integer.parseInt(UTmsgFrom[cid].readLine());
                    String fileName = UTmsgFrom[cid].readLine();
                    //System.out.println("get source id and filename");

                    // ask source about file
                    STmsgTo[source].println("give file");
                    STmsgTo[source].println(fileName);
                    boolean fileOk = Boolean.parseBoolean(STmsgFrom[source].readLine());
                    //System.out.println("ask source about file");

                    // telling receiver about file status
                    UTmsgTo[cid].println(Boolean.toString(fileOk));
                    //System.out.println("telling receiver about file");

                    if(fileOk) {
                        // get copy request from receiver
                        msg = UTmsgFrom[cid].readLine();
                        //System.out.println("receiver copy command");
                        if(msg.equals("yes copy")) {
                            System.out.println("Copying \'"+fileName+"\' from "+source+" to "+cid);
                            // tell sender to copy
                            STmsgTo[source].println("yes copy");
                            //System.out.println("tell sender copy command");

                            // copy from SENDER
                            // get file size
                            int FILE_SIZE = Integer.parseInt(STmsgFrom[source].readLine());
                            byte[] fileBytes = new byte[FILE_SIZE];
                            System.out.println("Get file size "+FILE_SIZE);
                            // get file data
                            int portion = STfileFrom[source].read(fileBytes,0,fileBytes.length);
                            int position = portion;
                            do {
                                portion = STfileFrom[source].read(fileBytes,position,fileBytes.length-position);
                                if(portion>=0) {
                                    position += portion;
                                }
                                System.out.println("position = "+position);
                            } while(position<FILE_SIZE);
                            System.out.println("Get file data "+position);

                            // copy to RECEIVER
                            // send file size
                            UTmsgTo[cid].println(Integer.toString(FILE_SIZE));
                            //System.out.println("send file size");
                            // send file data
                            UTfileTo[cid].write(fileBytes,0,position);
                            UTfileTo[cid].flush();
                            //System.out.println("send file data");
                            System.out.println("Copying \'"+fileName+"\' complete");
                        } else {
                            // tell sender to ignore copy process
                            STmsgTo[source].println("no copy");
                        }
                    }
                }
            } catch(Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}

客户端:

package client;
import java.io.*;
import java.net.*;

public class Client {

    public static void main(String[] args) throws Exception {
        String msg;
        InetAddress inetAddress = InetAddress.getLocalHost();
        String[] allPaths= {"H:\\Study\\Lab\\Network\\Assingment 2 and lab of 5 july\\Assignment\\files\\client_1_folder",
                            "H:\\Study\\Lab\\Network\\Assingment 2 and lab of 5 july\\Assignment\\files\\client_2_folder",
                            "H:\\Study\\Lab\\Network\\Assingment 2 and lab of 5 july\\Assignment\\files\\client_3_folder"};

        // connecting to welcome socket
        Socket server = new Socket(inetAddress,6000);
        BufferedReader receive = new BufferedReader(new InputStreamReader(server.getInputStream()));
        BufferedReader receiveUser = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter send = new PrintWriter(server.getOutputStream(),true);

        // receiving serial number
        int cid = Integer.parseInt(receive.readLine());

        // receiving port numbers for thread sockets
        int STport = Integer.parseInt(receive.readLine());
        int UTport = Integer.parseInt(receive.readLine());

        // connecting sockets
        Socket STsocket = new Socket(inetAddress,STport);
        Socket UTsocket = new Socket(inetAddress,UTport);

        System.out.println("Connected to the server.\nSerial: "+cid+"\nFolder path: "+allPaths[cid]);

        ServerThread st = new ServerThread(allPaths[cid],STsocket);
        UserThread ut = new UserThread(cid,allPaths[cid],UTsocket);
        st.start();
        ut.start();
    }
}

class UserThread extends Thread {
    int cid;
    String msg,folderPath;
    BufferedReader msgFromServer,fromUser;
    PrintWriter msgToServer;
    // for file
    DataInputStream fileFromServer;
    BufferedOutputStream writeFile;
    public UserThread(int cid,String folderPath,Socket socket) {
        try {
            this.cid = cid;
            this.folderPath = folderPath;
            fromUser = new BufferedReader(new InputStreamReader(System.in));
            msgFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            msgToServer = new PrintWriter(socket.getOutputStream(),true);
            // for file
            fileFromServer = new DataInputStream(socket.getInputStream());
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void run() {
        //System.out.println("User Thread Started!");
        while(true) {
            try {
                msg = fromUser.readLine();
                if(msg.equals("get list")) {
                    // sending request to server
                    msgToServer.println("get list");

                    // getting file list from server
                    System.out.println("-------------------------------------------");
                    for(int i=0; i<2; i++) {
                        // getting source id
                        int source = Integer.parseInt(msgFromServer.readLine());
                        System.out.println("Source: "+source);

                        int cnt = Integer.parseInt(msgFromServer.readLine());
                        System.out.println("Files: "+cnt);
                        System.out.println("--------------");

                        for(int j=0; j<cnt; j++) {
                            msg = msgFromServer.readLine();
                            System.out.println(msg);
                        }
                        System.out.println("-------------------------------------------");
                    }
                } else if(msg.equals("get file")) {
                    // GETTING A FILE
                    int source;
                    while(true) {
                        System.out.println("File Source: ");
                        try {
                            source = Integer.parseInt(fromUser.readLine());
                            if(0<=source && source<=2 && source!=cid) {
                                break;
                            } else {
                                System.out.println("Error: File source invalid. Try again.");
                            }
                        } catch(Exception ex) {
                            System.out.println("Error: File source invalid. Try again.");
                        }
                    }

                    System.out.println("File Name: ");
                    String fileName = fromUser.readLine();

                    // send request to server to check file
                    msgToServer.println("get file");
                    msgToServer.println(Integer.toString(source));
                    msgToServer.println(fileName);

                    // receiving file status
                    boolean fileOk = Boolean.parseBoolean(msgFromServer.readLine());
                    if(!fileOk) {
                        System.out.println("Error: File does not exist at source.");
                    } else {
                        System.out.println("File is available!!");
                        System.out.println("Want to copy \'"+fileName+"\'? (y/n)");
                        msg = fromUser.readLine();
                        if(msg.equals("y")||msg.equals("Y")) {
                            // tell server to copy file
                            msgToServer.println("yes copy");

                            // COPY PROCESS
                            // get file size
                            int FILE_SIZE = Integer.parseInt(msgFromServer.readLine());
                            System.out.println("File size: "+FILE_SIZE+" bytes.");
                            byte[] fileBytes = new byte[FILE_SIZE];

                            // get file data
                            int portion = fileFromServer.read(fileBytes,0,fileBytes.length);
                            int position = portion;
                            do {
                                portion = fileFromServer.read(fileBytes,position,fileBytes.length-position);
                                if(portion>=0) {
                                    position += portion;
                                }
                                System.out.println("position = "+position);
                            } while(position<FILE_SIZE);
                            System.out.println("Total "+position+" bytes received.");

                            // write file data
                            File file = new File(folderPath + "\\" + fileName);
                            writeFile = new BufferedOutputStream(new FileOutputStream(file));
                            writeFile.write(fileBytes,0,position);
                            writeFile.flush();
                            writeFile.close();

                            System.out.println("Copying complete.");
                        } else {
                            msgToServer.println("no copy");
                        }
                    }
                }
            } catch(Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}

class ServerThread extends Thread {
    String msg,folderPath;
    BufferedReader msgFromServer;
    PrintWriter msgToServer;
    // for file
    DataOutputStream fileToServer;
    BufferedInputStream readFile;
    public ServerThread(String folderPath,Socket socket) {
        try {
            this.folderPath = folderPath;
            msgFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            msgToServer = new PrintWriter(socket.getOutputStream(),true);
            // for file
            fileToServer = new DataOutputStream(socket.getOutputStream());
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void run() {
        //System.out.println("Server Thread Started!");
        while(true) {
            try {
                msg = msgFromServer.readLine();
                if(msg.equals("give list")) {
                    //System.out.println("Request from server: "+msg);
                    File folder = new File(folderPath);
                    File[] fileList = folder.listFiles();
                    int cnt = fileList.length;

                    //System.out.println("Files: "+cnt);

                    // give file count back to server
                    msgToServer.println(Integer.toString(cnt));

                    // give file list back to server
                    for(int i=0; i<cnt; i++) {
                        msgToServer.println(fileList[i].getName());
                    }
                } else if(msg.equals("give file")) {
                    // receive file name
                    String fileName = msgFromServer.readLine();

                    // telling server about file status
                    File file = new File(folderPath + "\\" + fileName);
                    boolean fileOk = file.exists();
                    msgToServer.println(Boolean.toString(fileOk));

                    if(fileOk) {
                        // getting copy request
                        msg = msgFromServer.readLine();
                        if(msg.equals("yes copy")) {
                            // COPY PROCESS
                            // send file size
                            int FILE_SIZE = (int)file.length();
                            msgToServer.println(Integer.toString(FILE_SIZE));

                            // read file data
                            readFile = new BufferedInputStream(new FileInputStream(file));
                            byte[] fileBytes = new byte[FILE_SIZE];
                            readFile.read(fileBytes,0,fileBytes.length);
                            readFile.close();

                            // send file data
                            fileToServer.write(fileBytes,0,fileBytes.length);
                            fileToServer.flush();
                        } // otherwise end of conversation
                    }
                }
            } catch(Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}

我知道我做了一些不必要的事情,比如给所有不同的套接字提供不同的端口。如果它们不是我问题的原因,请忽略它们。

1 个答案:

答案 0 :(得分:0)

ServerSocket.accept()是阻塞的,你不能从同一个线程中调用它两次。

每个ServerSocket都必须在自己的线程中运行。