Использование MS VC ++ C: 9 (2008) в Windows XP 32 бита и Boost.asio:
Я написал приложение, которое может отправлять / получать электронную почту с / на проприетарную базу данных dBase, используяПротоколы POP3 / SMTP.Все это работает, как и ожидалось, но в процессе подключения SMTP есть проблема, которую на данный момент мне не удалось устранить в общем виде.
В SMTP весь процесс представляет собой последовательностькоманды от клиента (C :) и чтение ответов с удаленного сервера (S :).Команда отправляется с некоторыми значениями:
async_write (socket_, request_,
boost::bind(&IPCON::hndlSOKresp, this, placeholders::error));
Ответ сервера на команду клиента всегда заканчивается последовательностью CRLF, поэтому функция hdlSOKresp () включает некоторые из них:
async_read (socket_, response_, transfer_at_least(1),
boost::bind(&IPCON::hndlRemain, this, placeholders::error));
В свою очередь, hadlRemain () проверяет, заканчивается ли принятый буфер парой CRLF, и в противном случае рекурсивно вызывает себя, пока не будет получен весь ответ.
Схема работает нормально, когда, как правило,Ответ сервера содержит одну строку, но команда EHLO / HELLO выдает многострочный ответ, содержащий основные характеристики сервера и специфику каждого сервера.Например, есть древовидные ответы:
1 & 1 Сервер Nemesis (провайдер интернет-услуг):
250-smtp.1and1.es
250-STARTTLS
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-PIPELINING
250-SIZE 120000000
250 HELP
Google Gmail:
250-mx.google.com at your service, [83.61.174.109]
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH
250 ENHANCEDSTATUSCODES
Yahoo:
250-smtp212.mail.bf1.yahoo.com
250-AUTH LOGIN PLAIN XYMCOOKIE
250-PIPELINING
250 8BITMIME
Вопрос в том, как можно справиться с этой ситуацией?
Временное решение состоит в том, что если я знаю используемое соединение, то я могу ждать до последнего слова.То есть: если используется Gmail, соединение может продолжить чтение, пока не будет получено слово «ENHANCEDSTATUSCODES \ r \ n», и весь процесс будет продолжен как чудо-вызов.Но очевидно, что это не практичный вариант.
Другой подход заключался в том, чтобы включить эту конкретную команду в блок try / catch и использовать таймер для прерывания процесса чтения через некоторое время.Например:
// the connection-object panelp is defined here -out of the try/catch block-
try {
if (!smtpConnect (panelp)) {
// throw some error…
}
} catch (...) {
// if (error == connection timed-out) then continue
}
// the process continues here
Проблема здесь в том, что если продолжить работу после исключения, процесс зависнет в следующей операции asio.Кажется, что раскрутка стека как-то повлияла на поведение asio.