2012-10-26 16 views
7

Mój problem polega na tym, że tworzę klienta FTP i jak na razie działa on bezbłędnie poza jednym drobnym szczegółem, który podsłuchuje mnie. Muszę wiedzieć, jak wiele linii obejmuje wiadomość powitalną FTP ... A to nie do zaakceptowania!Jak poznać koniec FTP Wiadomość powitalna

private Socket connection; 
    private PrintWriter outStream; 
    private Scanner inStream; 

public void InitiateConnection() throws IOException 
{ 
    log.Info(this, "Initiating connection to host: " + host + ":" + port); 
    connection = new Socket(host, port); 
    log.Info(this, "Connection initiated."); 
    outStream = new PrintWriter(connection.getOutputStream(), true); 
    inStream = new Scanner(connection.getInputStream()); 
    Listen(); 
    Listen();  
    Listen(); 
} 

public String Listen() throws IOException 
{ 
    if(connection == null) 
     throw new IOException("Connection not initiated yet"); 
    String response = inStream.nextLine(); 
    log.Info(this, "Response: " + response); 
    return response; 
} 

To jest prosta konfiguracja, pominięto wszystkie inne kody, ponieważ nie ma to nic wspólnego z moim problemem.

Próbowałem wielu rzeczy, aby spróbować to osiągnąć. Failed Rozwiązanie 1:

String response = ""; 
while(response != null) 
    Listen(); 

Failed Rozwiązanie 2:

while(connection.getInputStream().available > 0) 
    Listen(); 

i wiele innych ... Ale albo nie działa, albo metody blokowania i czekać na nowego wejścia. Próbowałem nawet z przekroczeniem limitu czasu, ale to też nie działa bezbłędnie, nie jest to właściwe rozwiązanie tego problemu ...

Potrzebuję być w stanie uzyskać całą wiadomość powitalną od serwera FTP, bez wiedzy ilość linii ... Więc mogę dostać to zarówno:

Response: 220-FileZilla Server version 0.9.39 beta 
Response: 220-written by Tim Kosse ([email protected]) 
Response: 220 Please visit http://sourceforge.net/projects/filezilla/ 

I tak:

Response: 220-FileZilla Server version 0.9.40 beta 
Response: 220 Welcome to Andrés FTP Server 

Odpowiedz

7

Jeśli masz dokładnie przyjrzeć wiadomości, widać, że wszystkie, ale ostatnie linie mają - za kodem stanu. Ostatnia linia ma numer , jednak wskazuje ostatnią linię.

można przeczytać, że w RFC 959, punkt 4.2:

Zatem format multi-line odpowiada to, że pierwsza linia rozpocznie się dokładnie wymagany kod odpowiedzi, a następnie natychmiast myślnikiem, "-" (znany również jako Minus), a następnie tekst: . Ostatnia linia rozpocznie się od tego samego kodu, a następnie natychmiast za pomocą spacji, opcjonalnie trochę tekstu i kodu końca linii Telnet .

Nie ma nic, co można powiedzieć o drugiej do ostatniej linii, ale logiczne jest, że mają ten sam format co pierwszy.


Aktualizacja: Protokół FTP wydaje się być źle udokumentowane, ale znalazłem innego odniesienia stwierdzające to samo jak ja powyżej:

TCP/IP Guide wspomina, że ​​

Możliwe jest post zawierać więcej niż jeden wiersz tekstu. W takim przypadku każda linia zaczyna się od kodu odpowiedzi, a wszystkie wiersze oprócz ostatniej mają łącznik między kodem odpowiedzi a tekstem odpowiedzi, aby wskazać, że odpowiedź jest kontynuowana. Ostatni wiersz zawiera spację między kodem odpowiedzi a tekstem odpowiedzi, podobnie jak w przypadku odpowiedzi jednoliniowej. Ta funkcja jest często wykorzystywana do dostarczania dodatkowych informacji o odpowiedzi po zalogowaniu się użytkownika za pomocą 230 kodu odpowiedzi.

+0

To jest * wieloliniowy * format odpowiedzi. Z tej samej sekcji: "Odpowiedź FTP składa się z trzycyfrowej liczby (przesłanej jako trzy znaki alfanumeryczne), po której następuje trochę tekstu." Z specyfikacji nie wynika jasno, ale jeśli uruchomisz FileZillę, zobaczysz, że jedyną odpowiedzią ML w procedurze connect jest odpowiedź 211 na polecenie FEAT. – linski

+0

zaktualizuje się odpowiednio jednak :) – linski

0

Czy próbowałeś tak?

StringBuilder response = new StringBuilder(); 
    BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); 
    do {    
     response.append(br.readLine());          
    } 
    while (br.ready()); 

Zważywszy ready() metodzie BufferedReader „s:

Informuje, czy strumień jest gotowy do odczytu. Buforowany strumień znaków jest gotowy, jeśli bufor nie jest pusty lub gotowy strumień znaków.
Powraca:
Prawda, jeśli następny read() jest gwarantowany, że nie blokuje wejścia, w przeciwnym razie false. Zwróć uwagę, że zwracanie wartości false nie gwarantuje, że następny odczyt zostanie zablokowany.

W rzeczywistości jest to 's method.

UPDATE:

Jak glglgl wskazał FTP istnieją dwa rodzaje odpowiedzi:

  • "linia pojedyncza" odpowiedź (mój termin)
  • multiline odpowiedź (Spec termin)

Jak powiedziałem w komentarzu, uruchom FIlleZillę, połącz i obserwuj dziennik (najlepiej porównując polecenia z wyjściem z definicją spec), a zobaczysz, dlaczego "pojedyncza linia" jest zacytowany.

W niektórych implementacjach serwera FTP powyższy kod może działać, ale nie będzie działać we wszystkich implementacjach, ponieważ nie implementuje poprawnie części klienta protokołu.Jest to zaktualizowana wersja:

String response; 
List<String> responseList = new ArrayList<String>(); 
boolean isMultilineStart = false, isMultilineEnd = false; 
String mlCode = null; 
do {    
    responseList.add(br.readLine());       
    if (!isMultilineStart) { 
     isMultilineStart = responseList.get(responseList.size()-1).matches("\\d\\d\\d-.*");     
     mlCode = responseList.get(responseList.size()-1).substring(0,3); 
    } 
    else { 
     isMultilineEnd = responseList.get(responseList.size()-1).startsWith(mlCode+" "); 
    } 
} 
while (br.ready() || (isMultilineStart && !isMultilineEnd)); 
response = Arrays.deepToString(responseList.toArray()); 
+0

Nie, nie, ale na pewno zamierzam to wypróbować. –

+1

Ale nie wiesz, czy serwer naprawdę skończył, czy też pakiet jest w drodze, ale jeszcze nie dotarł. Lepiej polegać na urządzeniach dostarczonych przez protokół. – glglgl

+0

@glglgl "Mój problem polega na tym, że tworzę klienta FTP ..." wygląda na to, że implementuje stronę klienta protokołu. – linski