Java - 通过套接字发送文件(聊天客户端 - >服务器 - >另一个聊天客户端)

时间:2012-12-31 15:36:21

标签: java swing file send java-io

所以我正在开发一个聊天程序,现在我想添加一个发送文件选项。 我尝试添加它并且它工作但文件传输完成后,两个套接字关闭(两个客户端的套接字)。 这是聊天客户端的SSCCE:

public class SSCCEChatClient extends JFrame {

    private JPanel contentPane;
    private JTextField inputUsernameField;
    private JTextArea textArea;
    String serversock = "84.252.37.82";
    String username;
    Socket sock;
    BufferedReader reader;
    PrintWriter writer;
    InputStreamReader streamreader;

    public class IncomingReader implements Runnable{

        public void run() {
            String stream;
            String[] data;

            try {
                while ((stream = reader.readLine()) != null) {

                    data = stream.split("`");
                     if(data[2].equals("receiveFile")&&(!data[3].equals(username))){
                        DataInputStream in = new DataInputStream(sock.getInputStream());
                        byte[] bytes = new byte[Integer.parseInt(data[1])];
                        in.read(bytes);
                        FileOutputStream fos = new FileOutputStream(System.getProperty("user.home") + "\\Desktop\\" + data[0]);
                        fos.write(bytes);
                        fos.close();
                        in.close();
                        textArea.append("Success!");
                    }else if(data[2].equals("server")){
                        textArea.append(data[0]);
                    }

                }
           }catch(Exception ex) {
           }
        }
    }//Incoming Reader

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    SSCCEChatClient frame = new SSCCEChatClient();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public SSCCEChatClient() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        textArea = new JTextArea();
        contentPane.add(textArea, BorderLayout.SOUTH);

        JButton btnNewButton = new JButton("Send File");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                File transferFile = new File (System.getProperty("user.home") + "\\Desktop\\PNG\\Night.png");
                byte [] bytearray  = new byte [(int)transferFile.length()];
                try {
                    BufferedInputStream bin = new BufferedInputStream(new FileInputStream(transferFile));
                    bin.read(bytearray,0,bytearray.length);
                    DataOutputStream os = new DataOutputStream(sock.getOutputStream());
                    writer.println(transferFile.getName() + "`" + transferFile.length() + "`receiveFile`" + username);
                    writer.flush();
                    os.write(bytearray,0,bytearray.length);
                    os.flush();
                    bin.close();
                    os.close();

                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.out.println("File transfer complete");
            }
        });
        contentPane.add(btnNewButton, BorderLayout.CENTER);

        JButton btnNewButton_1 = new JButton("Connect");
        btnNewButton_1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    username = inputUsernameField.getText();
                    sock = new Socket(serversock, 5000);
                    streamreader = new InputStreamReader(sock.getInputStream());
                    reader = new BufferedReader(streamreader);
                    writer = new PrintWriter(sock.getOutputStream());
                    Thread IncomingReader = new Thread(new IncomingReader());
                    IncomingReader.start();
                    writer.println(username + "``connect");
                    writer.flush();

                } catch (Exception ex) {
                    textArea.append("\nCannot Connect!");
                }
            }
        });
        contentPane.add(btnNewButton_1, BorderLayout.WEST);

        inputUsernameField = new JTextField();
        contentPane.add(inputUsernameField, BorderLayout.NORTH);
        inputUsernameField.setColumns(10);
    }

}

这是服务器端:

public class SSCCEServer {
    static ArrayList<PrintWriter> clientOutputStreams;
    static ArrayList<DataOutputStream> clientDataOutputStreams;
    static ArrayList<String> onlineUsers = new ArrayList<>();
    public class ClientHandler implements Runnable  {
        BufferedReader reader;
        Socket sock;
        PrintWriter client;


        public ClientHandler(Socket clientSocket, PrintWriter user) {
        // new inputStreamReader and then add it to a BufferedReader
            client = user;
            try {
                sock = clientSocket;
                System.out.println(clientSocket.getRemoteSocketAddress().toString() + " - ");
                InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
                reader = new BufferedReader(isReader);
            }
            catch (Exception ex) {
                System.out.println("error beginning StreamReader");
            }

        }

        public void run() {
            String message;
            String[] data;
            try {
                while ((message = reader.readLine()) != null) {

                    data = message.split("`");

                    if(data[2].equals("receiveFile")){
                        DataInputStream in = new DataInputStream(sock.getInputStream());
                        byte[] bytes = new byte[Integer.parseInt(data[1])];
                        in.read(bytes);
                        tellEveryone(data[0] + "`" + data[1] + "`" + data[2] + "`" + data[3]);
                        for(DataOutputStream dos:clientDataOutputStreams){
                            try {
                                dos.write(bytes);
                                dos.close();
                            }
                            catch (Exception ex) {
                                System.out.println("error telling everyone");
                            }
                        }
                        tellEveryone("File transfer complete``server");
                    }else if(data[2].equals("connect")){
                        System.out.println(data[0] + "has connected.");
                    }else {
                        System.out.println("No Conditions were met.");
                      }
                 }
            }
            catch (Exception ex) {
                System.out.println("lost a connection");
                System.out.println(ex.getMessage().toString());
                clientOutputStreams.remove(client);
            }
        }
    }
    public void tellEveryone(String message) {
    // sends message to everyone connected to server
        for(PrintWriter writer:clientOutputStreams){
                try {
                    writer.println(message);
                    //pop("Sending: " + message);
                    writer.flush();
                }
                catch (Exception ex) {
                    System.out.println("error telling everyone");
                }
        }
       }
    public static void main(String[] args) {
        new SSCCEServer().go();
    }
    public void go(){
        clientOutputStreams = new ArrayList<PrintWriter>();
        clientDataOutputStreams = new ArrayList<>();

        try {
            @SuppressWarnings("resource")
            ServerSocket serverSock = new ServerSocket(5000);
            while(true){
                Socket clientSock = serverSock.accept();
                PrintWriter writer = new PrintWriter(clientSock.getOutputStream());
                clientOutputStreams.add(writer);
                clientDataOutputStreams.add(new DataOutputStream(clientSock.getOutputStream()));
                Thread listener = new Thread(new ClientHandler(clientSock, writer));
                listener.start();
            }
        } 
        catch (Exception ex)
        {
            System.out.println("error making a connection");
        }
    }

}

很抱歉,如果它真的很长,但这是我可以带来的最小数量。此外,它不是整件事,因为它错过了发送文本方法但不影响SSCCE。我已经从服务器端使用'tellEveryone'方法演示了send方法。 此外,“\ PNG \ Night.png”只是一个示例,您可以创建自己的文件夹和文件以运行SSCCE。 在发送文件后,我该怎么做才能解决套接字的关闭问题?

2 个答案:

答案 0 :(得分:3)

  1. 关闭Objects区块中的所有finallytry - catch - finally

  2. 您遇到了Concurency in Swing的问题,但有三种方式

    a)正确的方法

    • 将代码包装到Runnable#Thread(最简单),必须将对Swing GUI的任何更改包装到invokeLater()

    • 使用SwingWorker(以标准方式实施),其中方法publishprocessdone非常确保所有events都已完成EDT

    b)快捷方式,有效但不合适

    • 将Swing GUI代码直接包装到invokeLater()

答案 1 :(得分:1)

关闭输出流时,套接字会关闭。如果要保持套接字打开,请不要关闭流。有关参考,请查看SocketOutputStream.java