2013-05-08 57 views
1

這些天,另一個挑戰使我頭痛不已。我正在嘗試在Java中創建一個應該能夠與FileZilla FTP客戶端進行通信的FTP服務器。代碼不是最好的,因爲我嘗試了很多事情來了解發生了什麼。Java到FileZilla FTP客戶端:套接字寫入錯誤

這裏的FileZilla記錄來自德國

Status: Connect to 127.0.0.1:21... 
Status: Connected!Waiting for welcome message. 
Response: 220 localhost connected 
Error: Establishing connection to server failed. 

主要問題到目前爲止轉化是建立真正的聯繫。套接字已連接,我可以向客戶端發送至少一條消息,但沒有機會獲得客戶端輸入,例如用於PASV,USER和PASS。

import java.awt.BorderLayout; 
import java.awt.Container; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.WindowEvent; 
import java.awt.event.WindowListener; 
import java.io.DataInputStream; 
import java.io.DataOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.net.SocketException; 

import javax.swing.JButton; 
import javax.swing.JFrame; 

public class FTP_Server extends JFrame implements ActionListener, WindowListener { 
    private static final long serialVersionUID = 1L; 

    private Container cp; 
    private JButton btncon; 
    private ServerSocket listenSocket; 
    private Socket connectionSocket; 
    private DataOutputStream dos; 
    private DataInputStream dis; 
    private OutputStream os; 
    private InputStream is; 

    public FTP_Server() { 
     super("FTP Server"); 

     this.setDefaultCloseOperation(EXIT_ON_CLOSE); 

     cp = this.getContentPane(); 
     cp.setLayout(new BorderLayout()); 

     btncon = new JButton("Connect"); 
     btncon.addActionListener(this); 

     cp.add(btncon, BorderLayout.CENTER); 

     this.pack(); 
     this.setVisible(true); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if(e.getSource().equals(btncon)){ 
      createConnection(); 
     } 
    } 

    public void createConnection() { 
     System.out.println("Connecting..."); 
     try { 
      listenSocket = new ServerSocket(21); 
      listenSocket.setSoTimeout(0); 
      connectionSocket = listenSocket.accept(); 
      connectionSocket.setSoLinger(true, 0); 
      connectionSocket.setSoTimeout(0); 
      connectionSocket.setKeepAlive(true); 
      System.out.println("Connected!"); 

      os = connectionSocket.getOutputStream(); 
      dos = new DataOutputStream(os); 

      is = connectionSocket.getInputStream(); 
      dis = new DataInputStream(is); 

      while(connectionSocket.isConnected() == true) { 
       dos.writeUTF("220 localhost connected\r\n"); 
       //Will cause socket write error soon! 
       dos.flush(); 
       dos.writeUTF("331 Anonym no password needed\r\n"); 
       System.out.println(is.read()); 
      } 
     } catch (SocketException exp) { 
      try { 
       listenSocket.close(); 
       System.out.println("Disconnected"); 
       exp.printStackTrace(); 
      } catch (IOException exp2) { 
       exp2.printStackTrace(); 
      } 
     } catch (IOException exp) { 
      exp.printStackTrace(); 
     } 
    } 

    @Override 
    public void windowOpened(WindowEvent e) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void windowClosing(WindowEvent e) { 
     System.exit(0); 
    } 

    @Override 
    public void windowClosed(WindowEvent e) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void windowIconified(WindowEvent e) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void windowDeiconified(WindowEvent e) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void windowActivated(WindowEvent e) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void windowDeactivated(WindowEvent e) { 
     // TODO Auto-generated method stub 

    } 
} 

對於錯誤消息/打印堆棧:

java.net.SocketException: Software caused connection abort: socket write error 
    at java.net.SocketOutputStream.socketWrite0(Native Method) 
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109) 
    at java.net.SocketOutputStream.write(SocketOutputStream.java:153) 
    at java.io.DataOutputStream.write(DataOutputStream.java:107) 
    at java.io.DataOutputStream.writeUTF(DataOutputStream.java:401) 
    at java.io.DataOutputStream.writeUTF(DataOutputStream.java:323) 
    at ftp.FTP_Server.createConnection(FTP_Server.java:82) 
    at ftp.FTP_Server.actionPerformed(FTP_Server.java:58) 
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018) 
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341) 
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402) 
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259) 
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252) 
    at java.awt.Component.processMouseEvent(Component.java:6505) 
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3321) 
    at java.awt.Component.processEvent(Component.java:6270) 
    at java.awt.Container.processEvent(Container.java:2229) 
    at java.awt.Component.dispatchEventImpl(Component.java:4861) 
    at java.awt.Container.dispatchEventImpl(Container.java:2287) 
    at java.awt.Component.dispatchEvent(Component.java:4687) 
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832) 
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492) 
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422) 
    at java.awt.Container.dispatchEventImpl(Container.java:2273) 
    at java.awt.Window.dispatchEventImpl(Window.java:2719) 
    at java.awt.Component.dispatchEvent(Component.java:4687) 
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:723) 
    at java.awt.EventQueue.access$200(EventQueue.java:103) 
    at java.awt.EventQueue$3.run(EventQueue.java:682) 
    at java.awt.EventQueue$3.run(EventQueue.java:680) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87) 
    at java.awt.EventQueue$4.run(EventQueue.java:696) 
    at java.awt.EventQueue$4.run(EventQueue.java:694) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:693) 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163) 
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139) 
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:97) 
+0

它在客戶端(Filezilla)上看起來如何? – 2013-05-08 12:23:08

+0

更新了主要問題;) – Jack 2013-05-09 13:14:40

+0

我的猜測是它是一個Filezilla打破了連接,不理解您的歡迎消息。但我不明白這是爲什麼。奇怪的是,我沒有找到「建立連接到服務器失敗」的消息int Filezilla代碼。你使用的是最新版本的Filezilla嗎?我不知道Java,所以不確定,如果'writeUTF'做了一些奇怪的事情(就像@EJP所建議的那樣)。但是,如果它只是以UTF編碼寫入字符串,則不應該因爲字符串是純ASCII而受到傷害。無論如何,你可以嘗試使用'writeChars'來代替。 – 2013-05-09 13:55:08

回答

0

我仍然遇到消息傳遞的問題。我現在做的是爲每個連接的套接字以及現在的每個輸出流創建一個新的線程。

package ftp; 

import java.io.DataOutputStream; 
import java.io.IOException; 

public class MultiIO implements Runnable{ 
    private DataOutputStream dos; 

    public MultiIO(DataOutputStream stream) { 
     dos = stream; 
     System.out.println("Set OutputStream."); 
    } 

    @Override 
    public void run() { 
     try { 
      dos.writeBytes("220"); 
      dos.flush(); 
      System.out.println("tried once"); 
     } catch (IOException e) { 
      System.exit(-1); 
     } 
    } 
} 

現在的問題是FileZilla客戶端不會得到220消息。

這裏是新的套接字處理類。我有點從甲骨文網頁複製它。

package ftp; 

import java.io.DataOutputStream; 
import java.io.IOException; 
import java.io.OutputStream; 
import java.net.Socket; 
import java.net.SocketException; 

public class MultiConnection implements Runnable{ 
    private Socket cSocket; 

    public MultiConnection(Socket client) { 
     cSocket = client; 
     System.out.println("Connected!"); 
    } 

    @Override 
    public void run() { 
     OutputStream os = null; 
     DataOutputStream dos = null; 
     try { 
      os = cSocket.getOutputStream(); 
      dos = new DataOutputStream(os); 
     } catch (SocketException es) { 
      es.printStackTrace(); 
     } catch (IOException e) { 
      System.exit(-1); 
     } 

     MultiIO mio; 
     mio = new MultiIO(dos); 
     Thread thio = new Thread(mio); 
     thio.start(); 
    } 
} 
+0

好的一個錯誤是忘記消息中的\ n。 – Jack 2013-05-10 09:36:04

+0

如果這是一個問題,請將其作爲問題發佈,而不是作爲答案。你不會以這種方式得到任何迴應。我建議你用這個「響應」替換原來的問題,並刪除響應。 – 2013-05-13 09:28:19

+0

這是一個解決方案。我的程序正在工作! – Jack 2013-05-15 16:22:40

0

許多錯誤這裏。

  1. 不要亂用SO_LINGER。這是沒有必要的,它只會導致更多的不必要的痛苦。
  2. writeUTF()寫入只讀readUTF()可以讀取的格式。這不是與非Java客戶端進行通信的一種方式。
  3. 您不是在單獨的線程中處理接受的套接字,因此您一次只能處理一個客戶端。
  4. isConnected()不是連接狀態的有效測試。它會告訴你你是否連接過這個插座。你做到了,所以它會迴歸真實。當對方斷開連接時,這不會改變。您需要以通常的方式測試EOS,並在各種讀取API中進行記錄。
  5. 當您在接受的套接字上發生IOException時,不需要關閉偵聽套接字。
  6. 我不明白爲什麼一個FTP服務器需要一個GUI,但是如果這樣做,它必須執行所有的網絡I/O,包括接受連接,在一個單獨的線程從AWT線程。
  7. 您只需要告訴客戶端他已成功連接一次,而不是無限次數。

這就足夠了。

+0

我幾乎認爲這個問題來自線程和缺少的線程。 gui只是爲了我,因爲如果懶得去做控制檯工作,我就傻了。感謝您對套接字的評論。我從來沒有用過學習如何在java中使用它們。 – Jack 2013-05-09 13:50:41

+0

我不認爲這與線程有關。雖然我不知道Java,但我相信我能夠理解代碼的好處,但這與代碼無關。這並不意味着你的代碼在線程方面通用。這不僅是你的直接問題的原因。 – 2013-05-09 14:03:02

+0

EOS代表什麼?服務結束? – Jack 2013-05-09 17:41:58