Модераторы: feodorv
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> WinSocket обработка ошибок протокола SMTP, WinSocket обработка ошибок протокола SMT 
:(
    Опции темы
Luchi
Дата 12.9.2012, 15:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 21.8.2012

Репутация: нет
Всего: нет



Доброго времени суток!
Пишу на C++ версия компилятора 2.95.2

Как грамотно проверять код на ошибки?
В SMTP клиенте с самого начала инициализации сокета и до конца программы SOCKET_ERROR==-1? Получается на протяжении всей программы в SOCKET_ERROR возвращается ошибка?
1. Или проверять нужно не SOCKET_ERROR, а send или recv? Но компилятор выдает ошибку.
2. Может кто-либо объясните простыми словами на одной части кода send и recv как проверять на ошибки, если можно конкретно на моем коде.
3. В каких переменных какие ошибки?
4. И есть ли разница что ставить в return -1, 0, 1 при обработке ошибки в IF() {return -1, 0, 1}?

Код

#include <conio.h>
#include <iostream>
#include <string>
#include <winsock.h>

int main()
{
    WSADATA ws;
    
    SOCKET s;
    struct sockaddr_in addr;
    hostent *d_addr;
    
    char text[1024];
    
    char * cstr;
    string str1, str2, str3;
    
    cout << SOCKET_ERROR << "\n";
    
    //инициализируем сокеты
    if (FAILED (WSAStartup (MAKEWORD( 1,1 ), &ws)))
    {
        printf("Error in WSAStartup(...)\n");
        return 1;
    }
    
    //создаем сокет
    s = socket (AF_INET,
                    SOCK_STREAM,
                    0
                    );
    if (s == INVALID_SOCKET)
    {
        //сообщение с номером ошибки
        printf("Error in socket(...)\n");
        WSACleanup();
        return 1;
    }
    
    //получаем адрес сервера
    d_addr = gethostbyname ("smtp.yandex.ru");
    if (d_addr == NULL)
    {
        printf("Error in gethostbyname(...)\n");
        closesocket(s);
        WSACleanup();
        return 1;
    };
    
    //заполняем параметры адреса
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = *((unsigned long *) d_addr->h_addr);
    addr.sin_port = htons (25);
    
    //устанавливаем соединение
    if (SOCKET_ERROR == (connect (s, (sockaddr *) &addr,
                                sizeof (addr))))
    {
        printf("Error in connect(...)\n");
        closesocket(s);
        WSACleanup();
        return 1;
    }
    
    //ждем ответ от сервера
    recv(s, text, sizeof(text), 0);
    printf("recv connect - %s\n", text);
    cout << SOCKET_ERROR << "\n";
    
    //приветствуем сервер
    strcpy(text, "EHLO smtp.yandex.ru\r\n");
    send(s, text, strlen(text), 0);
    printf("send EHLO - %s", text);
    recv(s, text, sizeof(text), 0);
    printf("recv EHLO - %s\n", text);
    cout << SOCKET_ERROR << "\n\n";
    if (SOCKET_ERROR == 0) //вместо -1 специально ставлю 0 или прогр закончится, хотя письмо приходит
    {
        closesocket(s);
        WSACleanup();
        
        printf("Invalid EHLO\n");
        getch();
        
        return 0;
    }
        
    strcpy(text, "AUTH LOGIN\r\n");
    send(s, text, strlen(text), 0);
    printf("send AUTH LOGIN - %s", text);
    recv(s, text, sizeof(text), 0);
    printf("recv AUTH LOGIN - %s\n", text);
    cout << SOCKET_ERROR << "\n\n";    

//login и password в base64 кодировке
    cout << "Login: ";
    cin >> str1;
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send LOGIN - %s", cstr);
    recv(s, text, sizeof(text), 0);
    printf("recv LOGIN - %s\n", text);
    cout << SOCKET_ERROR << "\n\n";
    
    delete[] cstr;
    
    cout << "Password: ";
    cin >> str1;
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send PASSWORD - %s", cstr);

    //ждем подтверждение от сервера
    recv(s, text, sizeof(text), 0);
    printf("recv PASSWORD - %s\n", text);
    cout << SOCKET_ERROR << "\n\n";
    
    if (SOCKET_ERROR == 0)
    {
        closesocket(s);
        WSACleanup();
        
        printf("Invalid Login or Password\n");
        getch();
        
        return 1;
    }
    
    delete[] cstr;
    
    //начинаем отправлять конверт состоящий из полей
    //MAIL FROM: и RCPT TO: После каждого поля ждем
    //подтверждение
    
    //сообщаем отправителя
    str1 = "MAIL FROM: ";
    cout << str1;
    cin >> str2;
    str1.append(str2);
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send - %s", cstr);
    
    //ждем подтверждение от сервера
    recv(s, text, sizeof(text), 0);
    printf("recv MAIL FROM - %s\n", text);
    cout << SOCKET_ERROR << "\n\n";
    
    if (SOCKET_ERROR == 0)
    {
        closesocket(s);
        WSACleanup();
        
        printf("Invalid Mail From\n");
        getch();
        
        return 1;
    }
    
    delete[] cstr;
    
    //сообщаем получателя
    str1 = "RCPT TO: ";
    cout << str1;
    cin >> str3;
    str1.append(str3);
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send - %s", cstr);
    
    //ждем подтверждение от сервера
    recv(s, text, sizeof(text), 0);
    printf("recv RCPT TO - %s\n", text);
    cout << SOCKET_ERROR << "\n\n";
    
    delete[] cstr;
    
    //подаем команду, что готовы начать передачу письма
    strcpy(text, "DATA\r\n");
    send(s, text, strlen(text), 0);
    printf("send - %s\n", text);
    
    //ждем подтверждение от сервера
    recv(s, text, sizeof(text), 0);
    printf("recv - %s", text);
    
    //передаем заголовок
    
    //от кого письмо
    str1 = "FROM: ";
    cout << str1;
    cin >> str2;
    str1.append(str2);
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send - %s", cstr);
    delete[] cstr;
    
    //кому письмо
    str1 = "TO: ";
    str1.append(str3);
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send - %s", cstr);
    delete[] cstr;
    
    //тема письма
    str1 = "SUBJECT: ";
    cout << "Tema mail: ";
    cin >> str2;
    str1.append(str2);
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n\r\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send - %s", cstr);
    delete[] cstr;
    
    //текст письма
    cout << "Text: ";
    cin >> str1;
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send - %s", cstr);
    delete[] cstr;
    
    //говорим, что закончили
    strcpy(text, "\r\n.\r\n");
    send(s, text, strlen(text), 0);
    printf("send - %s", text);
    recv(s, text, sizeof(text), 0);
    printf("recv - %s", text);
    
    //прощаемся с сервером
    strcpy(text, "QUIT");
    send(s, text, strlen(text), 0);
    printf("send - %s", text);
    
    //закрываем сокет
    closesocket(s);
    
    //деинициализирует сервис
    WSACleanup();
    
    printf("\n");
    printf("Press any key\n");
    getch();
    
    return 0;
}

PM MAIL   Вверх
feodorv
Дата 12.9.2012, 15:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Luchi @  12.9.2012,  16:11 Найти цитируемый пост)
В SMTP клиенте с самого начала инициализации сокета и до конца программы SOCKET_ERROR==-1? Получается на протяжении всей программы в SOCKET_ERROR возвращается ошибка?

SOCKET_ERROR есть константа, в неё возвращаться ничего не может. Как раз на неё проверяются возвращаемые значения функций - произошла ли ошибка или нет. Собственно код ошибки можно узнать из WSAGetLastError(). Поэтому условие
Цитата(Luchi @  12.9.2012,  16:11 Найти цитируемый пост)
    if (SOCKET_ERROR == 0)

всегда ложно.


Цитата(Luchi @  12.9.2012,  16:11 Найти цитируемый пост)
Или проверять нужно не SOCKET_ERROR, а send или recv?

Проверять нужно возвращаемые значения функций send или recv:
Код

if( (bytes = recv(...)) == SOCKET_ERROR ) printf( "Error of recv(): %u\n", WSAGetLastError());



Цитата(Luchi @  12.9.2012,  16:11 Найти цитируемый пост)
4. И есть ли разница что ставить в return -1, 0, 1 при обработке ошибки в IF() {return -1, 0, 1}?

Если Ваша программа не выполняется из под скрипта или другой программы, в которых проверяется это значение, то не имеет.
Но в духе "хорошего стиля программирования" в случае ошибки лучше возвращать из main() не 0, в случае успеха - 0.
Можно даже последовать рекомендациям Microsoft, и возвращать значения специально определённых кодов.

Добавлено через 10 минут и 58 секунд
Хочу также заметить, что SMTP сервер не обязан возвращать строки, заканчивающиеся символом '\0', поэтому такой код:
Цитата(Luchi @  12.9.2012,  16:11 Найти цитируемый пост)
    recv(s, text, sizeof(text), 0);
    printf("recv AUTH LOGIN - %s\n", text);

может выполниться с непредсказуемым результатом. Лучше написать так:
Код

    int bytes;
    if( (bytes = recv( s, text, sizeof(text)-1, 0)) < 0 )
    {
       /* Error */
       return -1;
    }
    text[bytes] = '\0';
    printf("recv AUTH LOGIN - %s\n", text);



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Luchi
Дата 12.9.2012, 18:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 21.8.2012

Репутация: нет
Всего: нет



feodorv
Спасибо объяснил доступно, код который получился ниже.
1. ф-и send и recv возвращают много значений, нужно проверять каждое? Как узнать какое значение чему соотвествует?
2. Почему WSAGetLastError() постоянно показывает 0?
3. Если в PASSWORD if ((er = recv(s, text, sizeof(text), 0)) == SOCKET_ERROR ), при вводе неправильного пароля if не срабатывает и программа не завершается, хотя ведь с сервера приходит ошибка? er в этом случае = больше 1, тогда зачем в случае ошибки сравнивать er<0?
4. Помню в справочниках указывалось, что при проверках на ошибки всего 2-3 значения: 1-все правильно, 0-нет данных, -1-ошибка, или без 0?
5. Нужно ли проверять на ошибки заголовки письма?

Код

#include <conio.h>
#include <iostream>
#include <string>
#include <winsock.h>

int main()
{
    WSADATA ws;
    
    SOCKET s;
    struct sockaddr_in addr;
    hostent *d_addr;
    
    char text[1024];
    
    char * cstr;
    string str1, str2, str3;
    int er;
    
    //инициализируем сокеты
    if (FAILED (WSAStartup (MAKEWORD( 1,1 ), &ws)))
    {
        printf("Error in WSAStartup(...)\n");
        return -1;
    }
    
    //создаем сокет
    s = socket (AF_INET,
                    SOCK_STREAM,
                    0
                    );
    if (s == INVALID_SOCKET)
    {
        //сообщение с номером ошибки
        printf("Error in socket(...)\n");
        WSACleanup();
        return -1;
    }
    
    //получаем адрес сервера
    d_addr = gethostbyname ("smtp.yandex.ru");
    if (d_addr == NULL)
    {
        printf("Error in gethostbyname(...)\n");
        closesocket(s);
        WSACleanup();
        return -1;
    };
    
    //заполняем параметры адреса
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = *((unsigned long *) d_addr->h_addr);
    addr.sin_port = htons (25);
    
    //устанавливаем соединение
    if (SOCKET_ERROR == (connect (s, (sockaddr *) &addr,
                                sizeof (addr))))
    {
        printf("Error in connect(...)\n");
        closesocket(s);
        WSACleanup();
        return -1;
    }
    
    //ждем ответ от сервера
    er = recv(s, text, sizeof(text), 0);
    cout << "recv connect " << er << "\n";
    printf("recv connect - %s", text);
    printf("WSAGetLastError() - %d\n\n", WSAGetLastError());
    
    
    
    //приветствуем сервер
    strcpy(text, "EHLO smtp.yandex.ru\r\n");
    
    if ((er = send(s, text, strlen(text), 0)) < 0 )
    {
        printf("Error of EHLO send(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "send EHLO " << er << "\n";
    printf("send EHLO - %s", text);
    printf("WSAGetLastError() - %d\n", WSAGetLastError());
    
    //ждем подтверждение от сервера
    if ((er = recv(s, text, sizeof(text), 0)) < 0 )
    {
        printf("Error of EHLO recv(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "recv EHLO " << er << "\n";
    printf("recv EHLO - %s", text);
    printf("WSAGetLastError() - %d\n\n", WSAGetLastError());
    
    
    
    strcpy(text, "AUTH LOGIN\r\n");
    
    if ((er = send(s, text, strlen(text), 0)) < 0 )
    {
        printf("Error of AUTH LOGIN send(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "send AUTH LOGIN " << er << "\n";
    printf("send AUTH LOGIN - %s", text);
    printf("WSAGetLastError() - %d\n", WSAGetLastError());
    
    //ждем подтверждение от сервера
    if ((er = recv(s, text, sizeof(text), 0)) < 0 )
    {
        printf("Error of AUTH LOGIN recv(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "recv AUTH LOGIN " << er << "\n";
    printf("recv AUTH LOGIN - %s", text);
    printf("WSAGetLastError() - %d\n\n", WSAGetLastError());
    
    
    
    cout << "LOGIN: ";
    cin >> str1;
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    
    if ((er = send(s, cstr, strlen(cstr), 0)) < 0 )
    {
        printf("Error of LOGIN send(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "send LOGIN " << er << "\n";
    printf("send LOGIN - %s", cstr);
    printf("WSAGetLastError() - %d\n", WSAGetLastError());
    
    //ждем подтверждение от сервера
    if ((er = recv(s, text, sizeof(text), 0)) < 0 )
    {
        printf("Error of LOGIN recv(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "recv LOGIN " << er << "\n";
    printf("recv LOGIN - %s", text);
    printf("WSAGetLastError() - %d\n\n", WSAGetLastError());
    
    delete[] cstr;
    
    
    
    cout << "Password: ";
    cin >> str1;
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    
    if ((er = send(s, cstr, strlen(cstr), 0)) < 0 )
    {
        printf("Error of PASSWORD send(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "send PASSWORD " << er << "\n";
    printf("send PASSWORD - %s", cstr);
    printf("WSAGetLastError() - %d\n", WSAGetLastError());
    
    //ждем подтверждение от сервера
    if ((er = recv(s, text, sizeof(text), 0)) < 0 )
    {
        printf("Error of PASSWORD recv(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "recv PASSWORD " << er << "\n";
    printf("recv PASSWORD - %s", text);
    printf("WSAGetLastError() - %d\n\n", WSAGetLastError());
    
    delete[] cstr;
    
    
    
    //начинаем отправлять конверт состоящий из полей
    //MAIL FROM: и RCPT TO: После каждого поля ждем
    //подтверждение
    
    //сообщаем отправителя
    str1 = "MAIL FROM: ";
    cout << str1;
    cin >> str2;
    str1.append(str2);
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    
    if ((er = send(s, cstr, strlen(cstr), 0)) < 0 )
    {
        printf("Error of MAIL FROM send(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "send MAIL FROM " << er << "\n";
    printf("send MAIL FROM - %s", cstr);
    printf("WSAGetLastError() - %d\n", WSAGetLastError());
    
    //ждем подтверждение от сервера
    if ((er = recv(s, text, sizeof(text), 0)) < 0 )
    {
        printf("Error of MAIL FROM recv(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "recv MAIL FROM " << er << "\n";
    printf("recv MAIL FROM - %s", text);
    printf("WSAGetLastError() - %d\n\n", WSAGetLastError());
    
    delete[] cstr;
    
    
    
    //сообщаем получателя
    str1 = "RCPT TO: ";
    cout << str1;
    cin >> str3;
    str1.append(str3);
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    
    if ((er = send(s, cstr, strlen(cstr), 0)) < 0 )
    {
        printf("Error of RCPT TO send(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "send RCPT TO " << er << "\n";
    printf("send RCPT TO - %s", cstr);
    printf("WSAGetLastError() - %d\n", WSAGetLastError());
    
    //ждем подтверждение от сервера
    if ((er = recv(s, text, sizeof(text), 0)) < 0 )
    {
        printf("Error of RCPT TO recv(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "recv RCPT TO " << er << "\n";
    printf("recv RCPT TO - %s", text);
    printf("WSAGetLastError() - %d\n\n", WSAGetLastError());
    
    delete[] cstr;
    
    
    
    //подаем команду, что готовы начать передачу письма
    strcpy(text, "DATA\r\n");
    
    if ((er = send(s, text, strlen(text), 0)) < 0 )
    {
        printf("Error of DATA send(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "send DATA " << er << "\n";
    printf("send DATA - %s", text);
    printf("WSAGetLastError() - %d\n", WSAGetLastError());
    
    //ждем подтверждение от сервера
    if ((er = recv(s, text, sizeof(text), 0)) < 0 )
    {
        printf("Error of DATA recv(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "recv DATA " << er << "\n";
    printf("recv DATA - %s", text);
    printf("WSAGetLastError() - %d\n\n", WSAGetLastError());
    
    
    
    //передаем заголовок
    
    //от кого письмо
    str1 = "FROM: ";
    cout << str1;
    cin >> str2;
    str1.append(str2);
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send - %s", cstr);
    delete[] cstr;
    
    //кому письмо
    str1 = "TO: ";
    str1.append(str3);
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send - %s", cstr);
    delete[] cstr;
    
    //тема письма
    str1 = "SUBJECT: ";
    cout << "Tema mail: ";
    cin >> str2;
    str1.append(str2);
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\r\n\r\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send - %s", cstr);
    delete[] cstr;
    
    //текст письма
    cout << "Text: ";
    cin >> str1;
    cstr = new char [str1.size()+1];
    strcpy (cstr, str1.c_str());
    strcat(cstr, "\n");
    send(s, cstr, strlen(cstr), 0);
    printf("send - %s", cstr);
    delete[] cstr;
    
    //говорим, что закончили
    strcpy(text, "\r\n.\r\n");
    
    if ((er = send(s, text, strlen(text), 0)) < 0 )
    {
        printf("Error of END send(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "send END " << er << "\n";
    printf("send END - %s", text);
    printf("WSAGetLastError() - %d\n", WSAGetLastError());
    
    //ждем подтверждение от сервера
    if ((er = recv(s, text, sizeof(text), 0)) < 0 )
    {
        printf("Error of END recv(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "recv END " << er << "\n";
    printf("recv END - %s", text);
    printf("WSAGetLastError() - %d\n\n", WSAGetLastError());
    
    
    
    //прощаемся с сервером
    strcpy(text, "QUIT");
    
    if ((er = send(s, text, strlen(text), 0)) < 0 )
    {
        printf("Error of QUIT send(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }
    text[er] = '\0';
    cout << "send QUIT " << er << "\n";
    printf("send QUIT - %s\n", text);
    printf("WSAGetLastError() - %d\n", WSAGetLastError());
    
    
    
    //закрываем сокет
    closesocket(s);
    
    //деинициализирует сервис
    WSACleanup();
    
    printf("\n");
    printf("Press any key\n");
    getch();
    
    return 0;
}


Это сообщение отредактировал(а) Luchi - 12.9.2012, 20:04
PM MAIL   Вверх
feodorv
Дата 12.9.2012, 20:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Luchi @  12.9.2012,  19:40 Найти цитируемый пост)
1. ф-и send и recv возвращают много значений, нужно проверять каждое? Как узнать какое значение чему соотвествует?

Функции send и recv возвращают либо ошибку (ту самую константу SOCKET_ERROR), либо число байт, посланных или прочитанных. Так что возвращаемое значение всего одно.


Цитата(Luchi @  12.9.2012,  19:40 Найти цитируемый пост)
4. Помню в справочниках указывалось, что при проверках на ошибки всего 2-3 значения: 1-все правильно, 0-нет данных, -1-ошибка, или без 0?

Не знаю, что за справочники Вы читали. Самое главное упущено - "число байт, посланных или прочитанных" (если не ошибка).
При синхронных (а у Вас везде синхронные) операциях recv, да, возвращает 0, если соединение входит в стадию разрыва, ожидать при этом прихода новых данных бессмысленно. send может вернуть 0, если Вы попросили послать 0 байт. В остальном - "число байт, посланных или прочитанных" (если не ошибка).


Цитата(Luchi @  12.9.2012,  19:40 Найти цитируемый пост)
2. Почему WSAGetLastError() постоянно показывает 0?

Просто, абстрактно вызывать WSAGetLastError() смысла нет, этот вызов всё равно вернёт код последней возникшей ошибки (или могущей возникнуть в зависимости от использовавшегося вызова WinSock API). Если ошибок не возникало, WSAGetLastError() будет постоянно возвращать 0. То есть контекст вызова WSAGetLastError() такой:
Код

  if( ...error... )
  {
     ... WSAGetLastError() ...
  }



Цитата(Luchi @  12.9.2012,  19:40 Найти цитируемый пост)
3. Если в PASSWORD if ((er = recv(s, text, sizeof(text), 0)) == SOCKET_ERROR ), при вводе неправильного пароля if не срабатывает и программа не завершается, хотя ведь с сервера приходит ошибка? er в этом случае = больше 1, тогда зачем в случае ошибки сравнивать er<0?

Идёт проверка ошибки вызова recv на Вашей стороне. Мало ли что могло случиться. Сервер мог разорвать соединение, кто-то мог передёрнуть маршрутизатор или вообще выдернуть сетевой кабель. ОС на всё это реагирует, возвращая Вам SOCKET_ERROR в recv() и устанавливая соответствующий код ошибки в WSAGetLastError(). 
И send совершенно не знает, что Вы отправляете в сеть, пароль ли, признание в любви или ещё что. Он/оно просто отправляет в сеть то, что попросили. Если ли же на стороне сервера пароль не прошёл проверку, то SMTP сервер пришлёт обратно сообщение вида "Password incorrect" или ещё что-то в этом роде. При этом recv отработает штатно, без ошибок, и прочтёт из сети это сообщение. И уже Ваша задача (на прикладном уровне!) обработать это сообщение корректно. recv здесь вообще не причём... 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Luchi
Дата 13.9.2012, 22:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 21.8.2012

Репутация: нет
Всего: нет



@feodorv
Спасибо, понятно. Единственное, когда отправляю логин и пароль, идет простой обмен данными, чтобы корректно на прикладном уровне обработать сообщение, при неправильном логин или пароль (в этой ситуации приходит 67 байт) нужно:

Код

    if ((er = recv(s, text, sizeof(text), 0)) == 67 )
    {
        printf("Error of PASSWORD recv(): %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return -1;
    }


Но ведь ответы разных серверов могут отличаться, поэтому кол-во байт тоже будет различаться. Если не сложно, как универсально обработать ошибку логина или пароля? Во всех найденных материалах касаемых сокетов именно этот момент не расписан.

Это сообщение отредактировал(а) Luchi - 13.9.2012, 22:59
PM MAIL   Вверх
feodorv
Дата 14.9.2012, 21:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Luchi @  13.9.2012,  23:21 Найти цитируемый пост)
в этой ситуации приходит 67 байт

Нет-нет. Не нужно строго ориентироваться на число присланных байт. При правильном логине/пароле сервер пришлёт подтверждение. Если такое подтверждение не получено, можно считать, что регистрация не прошла.

Сам ответ от сервера содержится в text (в конце концов, Вы же читаете из сети именно в text). Вот содержимое этого буфера и нужно анализировать. Например:
Код

text[er] = '\0';
if( strncmp( text, "235 ", 4) != 0 )
{
  printf( "Login/password incorrect: %s\n", text);
  return -1;
}


Цитата(Luchi @  13.9.2012,  23:21 Найти цитируемый пост)
Но ведь ответы разных серверов могут отличаться

Подтверждение регистрации стандартизировано (нужно смотреть спецификацию протокола SMTP, это какой-то RFC).
Честно, сам я не помню, какой именно ответ должен быть от сервера в случае успеха, но он всегда одинаков и не зависит от сервера. Отрицательный ответ может варьироваться...


Это сообщение отредактировал(а) feodorv - 14.9.2012, 21:47


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Luchi
Дата 14.9.2012, 21:48 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 21.8.2012

Репутация: нет
Всего: нет



feodorv

Вот это я и искал. Решил эту задачу с помощью ф-и atoi():
Код

recv(s, text, sizeof(text), 0);
if (atoi(text) == 502 || 535)
{
    closesocket(s);
    WSACleanup();
    printf("Invalid LOGIN or PASSWORD\n");
    return -1;
}


Но за ваш вариант спасибо, буду иметь ввиду.
PM MAIL   Вверх
feodorv
Дата 15.9.2012, 02:37 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Luchi @  14.9.2012,  22:48 Найти цитируемый пост)
Но за ваш вариант спасибо, буду иметь ввиду. 

По сути, мой ответ ничем не отличается от Вашего решения  smile 
Но! Опять-таки:
Цитата(Luchi @  14.9.2012,  22:48 Найти цитируемый пост)
recv(s, text, sizeof(text), 0);

Вы не завершили данные буфера text символом конца строки '\0'. В результате функция atoi может вернуть всё, что угодно (есть такая вероятность).


Цитата(Luchi @  14.9.2012,  22:48 Найти цитируемый пост)
if (atoi(text) == 502 || 535)

Посмотрите, пожалуйста, на этот код внимательно. Что не так?


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Luchi
Дата 17.9.2012, 19:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 21.8.2012

Репутация: нет
Всего: нет



Цитата(feodorv @  15.9.2012, 02:37 Найти цитируемый пост)
По сути, мой ответ ничем не отличается от Вашего решения

Согласен, но для того чтобы разобраться и научиться, лучше иметь несколько вариантов решения задачи.

Цитата(feodorv @  15.9.2012, 02:37 Найти цитируемый пост)
Вы не завершили данные буфера text символом конца строки '\0'. В результате функция atoi может вернуть всё, что угодно (есть такая вероятность)

У меня \0 стоял после фразы и я его не включил, но как сейчас понимаю, что он вообще не на своем месте стоял, т.к. его вставка должна произойти до выполнения ф-и.
Код

recv(s, text, sizeof(text), 0);
if (atoi(text) == 502 || 535)
{
    closesocket(s);
    WSACleanup();
    printf("Invalid LOGIN or PASSWORD\n");
    return -1;
}
text[er] = '\0';
printf("recv - %s\n", text);


Цитата(feodorv @  15.9.2012, 02:37 Найти цитируемый пост)
Посмотрите, пожалуйста, на этот код внимательно. Что не так?

Думаю, что этот код не универсален, т.к. обрабатываются только два варианта ответа.

Переработанный код:
с использованием atoi
Код

er = recv(s, text, sizeof(text), 0);
text[strlen(text)] = '\0'; //если вставить text[er] = '\0', то ответ сервера будет урезан до одной строки
if (atoi(text) != 334)
{
    cout << "recv AUTH LOGIN " << er << "\n";
    printf("recv AUTH LOGIN - %s\n", text);
    printf("Error of AUTH LOGIN recv(): %d\n", WSAGetLastError());
    send(s, "QUIT", 4, 0);
    closesocket(s);
    WSACleanup();
    printf("Press any key for exit\n");
    getch();
    return -1;
}
cout << "recv AUTH LOGIN " << er << "\n";
printf("recv AUTH LOGIN - %s\n", text);

с использованием strncmp
Код

er = recv(s, text, sizeof(text), 0);
text[strlen(text)] = '\0'; //если вставить text[er] = '\0', то ответ сервера будет урезан до одной строки
if (strncmp(text, "334 ", 4) != 0)
{
    cout << "recv LOGIN " << er << "\n";
    printf("recv LOGIN - %s\n", text);
    printf("Incorrect of LOGIN recv(): %d\n", WSAGetLastError());
    send(s, "QUIT", 4, 0);
    closesocket(s);
    WSACleanup();
    printf("Press any key for exit\n");
    getch();
    return -1;
}
cout << "recv LOGIN " << er << "\n";
printf("recv LOGIN - %s\n", text);


Это сообщение отредактировал(а) Luchi - 17.9.2012, 19:38
PM MAIL   Вверх
feodorv
Дата 17.9.2012, 20:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Luchi @  17.9.2012,  20:32 Найти цитируемый пост)
recv(s, text, sizeof(text), 0);
if (atoi(text) == 502 || 535)
{
    closesocket(s);
    WSACleanup();
    printf("Invalid LOGIN or PASSWORD\n");
    return -1;
}
text[er] = '\0';
printf("recv - %s\n", text);

Функция atoi реагирует на '\0', поэтому присвоение text[er] = '\0'; нужно делать ДО вызова atoi. Соответственно, при чтении из сокета необходимо зарезервировать один байт под этот самый '\0', поэтому в recv нужно указывать sizeof(text)-1.


Цитата(Luchi @  17.9.2012,  20:32 Найти цитируемый пост)
Думаю, что этот код не универсален, т.к. обрабатываются только два варианта ответа.

Дело не в этом. Конструкция 
Цитата(Luchi @  17.9.2012,  20:32 Найти цитируемый пост)
if (atoi(text) == 502 || 535)

воспринимается компилятором совсем не так, как Вы задумали. Вы думали про что-то такое:
Код

if (atoi(text) == 502 || atoi(text) == 535)

А у Вас получилось так:
Код

BOOL condition = FALSE;
if( atoi(text) == 502 ) condition = TRUE;
if( 535 ) condition = TRUE;
if( condition )

Условие всегда истинно, не понятно, как у Вас программа работала...


Цитата(Luchi @  17.9.2012,  20:32 Найти цитируемый пост)
text[strlen(text)] = '\0'; //если вставить text[er] = '\0', то ответ сервера будет урезан до одной строки

Сам по себе код text[strlen(text)] = '\0'; совершенно бессмысленнен (и даже опасен) и говорит о том, что Вы не понимаете, что такое си-строка, как работает strlen и прочая...


Цитата(Luchi @  17.9.2012,  20:32 Найти цитируемый пост)
с использованием strncmp

Если вы закрыли строку, прочитанную из сети, завершающим символом '\0', то уже всё равно, что atoi, что strncmp. Если же нет, тогда только strncmp smile 


Цитата(Luchi @  17.9.2012,  20:32 Найти цитируемый пост)
ответ сервера будет урезан до одной строки

Ээээ. Пожалуйста, поподробнее. Покажите, пожалуйста, что Вы шлёте, и чем отвечает сервер (это всё можно сделать через printf'ы).

Добавлено через 4 минуты и 9 секунд
Цитата(Luchi @  17.9.2012,  20:32 Найти цитируемый пост)
er = recv(...);

И всё-таки, неверный подход к функции recv. Она возвращает число прочитанных байт, поэтому стилистически правильнее было бы использование переменной с именем bytes:
Код

bytes = recv(...);

А Вы ожидаете ошибку, которая возникает крайне редко smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.1752 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.