2012-12-31 244 views
3

所以我正在開發一個聊天程序,現在我想添加一個發送文件選項。 我試着添加它,它的工作,但在文件傳輸完成後,兩個套接字關閉(兩個客戶端的套接字)。 下面是聊天客戶端的SSCCE:Java - 通過套接字發送文件(聊天客戶端 - >服務器 - >另一個聊天客戶端)

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。 我能做些什麼來修復文件發送後套接字的關閉?

+0

如何使我的代碼更好,請在codereview.SE中。關於套接字關閉,你複製一個更簡潔的問題http://stackoverflow.com/questions/2826311/writing-to-socket-outputstream-w-o-closing-it – Val

回答

3
  1. 關閉所有Objectsfinally塊(try - catch - finally

  2. 你有問題與Concurency in Swing,但有三種方式

    一)適當方式

    • 將代碼換成Runnable#Thread(最簡單的),必須對Swing GUI的任何更改包裝成invokeLater()

    • 使用SwingWorker(以標準的方式來實現),其中方法publishprocessdone相當保函所有events是在EDT

    完成

    b)的快捷方式,作品但不正確的方式

    • 包裝的Swing GUI代碼爲invokeLater()直接
1

關閉輸出流時,套接字關閉。如果您想保持套接字打開,請不要關閉流。對於參考看看SocketOutputStream.java