Как определить конец ответа SMTP и POP?

#java #sockets #smtp #pop3

#java #сокеты #smtp #pop3

Вопрос:

Я читаю посимвольно ответ сокета в BufferedReader, записанный из сокета, который я подключаю к серверу SMTP и POP. Но как мне узнать, прочитал ли я до конца ответ, чтобы избежать read() зависания для чтения сверх того, что ответил сервер? Следующий код — это то, как я читаю из BufferedReader:

 boolean endOfResponse = false;
while(!endOfResponse) {
    c = in.read();
    if ((c >= 32 amp;amp; c < 127) || c == 't' || c == 'r' || c == 'n') { 
        response.append((char)c);
        //The following check has a problem: If the response has multiple lines, the other lines will not be read.
        if(c == 'n') endOfResponse = true;
    }
}
  

Например, в POP, когда я выполняю a LIST , ответ заканчивается на . . Но в SMTP, когда я выполняю EHLO , это не дает четкого указания на то, когда ответ закончился.

Использование in.read() == -1 , к сожалению, не работает, поскольку оно все равно будет пытаться прочитать ответные данные и приведет к зависанию сокета.

Итак, как мне определить конец ответа SMTP и POP? Еще лучше, возможно ли заранее узнать, сколько байтов я должен прочитать из буфера, чтобы мне даже не пришлось проверять конец ответа?

Комментарии:

1. Знаете ли вы, что существует JavaMail, реализующий все эти протоколы и обеспечивающий уровень абстракции над ними? oracle.com/technetwork/java/javamail/index.html . Даже если вы не хотите его использовать, он с открытым исходным кодом, поэтому вы можете захотеть посмотреть, как он работает внутри.

Ответ №1:

Эти 2 протокола отличаются, но оба отправляют сообщения, которые заканчиваются новой строкой. С помощью SMTP вы читаете по 1 строке за раз (заканчивающейся на n), каждая прочитанная вами строка должна начинаться с 3 цифр, затем либо с пробела, либо с ‘-‘, если это пробел, то это конец ответа сервера, если это ‘-‘ (например 250-VRFY , что вы получили бы, если бы вы открылись с помощью EHLO, предлагая серверу ответить списком расширенных команд ESMTP), затем вам нужно прочитать другую строку.

Я полагаю, что в POP3 это зависит от команды, которую вы выдаете. Что-то вроде USER или PASS выдает вам ответ ‘ ‘ или ‘-‘ (за которым следует код и некоторый текст). Команда типа LIST выдает вам ‘ ‘ или ‘-‘, и если ‘ ‘, вы получаете свой список электронных писем, который сам по себе будет заканчиваться одним ‘.’. Каждый из этих ответов (а также каждый индекс электронного письма) будет представлять собой строку.

Вам следует взглянуть на RFC 821 для SMTP и RFC 1939 для POP3, чтобы получить подробное описание протоколов

Комментарии:

1. Итак, в POP разные команды имеют разные окончания? Для LIST и RETR у них есть . для end. Но для определенных команд, таких как USER и PASS, ответ не заканчивается на . . Итак, в моем коде я должен различать разные команды и не могу иметь общий способ чтения ответа для всех команд?

2. Да, вам нужно знать, ожидаете ли вы многострочный ответ с POP3. Например, если вы выдаете список, вы должны читать, пока не получите «.» в отдельной строке. Даже если перечислять нечего.

3. Джордан Стюарт опубликовал более актуальный RFC.

Ответ №2:

В SMTP конец ответа от серверной части транзакции можно определить, посмотрев на символ после кода ответа: это ‘-‘ после кода состояния в каждой строке ответа, за исключением последней строки—

 Client: EHLO my.mailserver.com
Server: 123-This is a
Server: 123 Multi-line response
  

Итак, для SMTP (я раньше не имел дела с POP, но, похоже, вы с этим разобрались!) вам нужно будет проверить наличие этого символа ‘-‘ после кода состояния, чтобы определить, есть ли еще строки в ответе.

Текущий RFC SMTP (5321) документирует это: https://www.rfc-editor.org/rfc/rfc5321 (например, страница 32)