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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Несколько send и recv 
:(
    Опции темы
Alexey91
  Дата 11.5.2012, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Здравствуйте!

Выполняю следующую последовательность команд

send (user .... 
send (pass ...
send (stat ....
recv

Когда вывожу буфер от recv выводится всякая абракадабра.
Я ожидал увидеть, что мне прислал сервер от последнего send'a
Не понимаю почему так происходит.

И тогда я правильно понимаю, что необходимо выгружать данные в буфер после каждого send, т.е.

send (user .... 
recv
send (pass ...
recv
send (stat ....
recv

?
PM   Вверх
boostcoder
Дата 11.5.2012, 18:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

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



сокет блокирующий?
вообще, покажи код отправки user/pass/stat
PM WWW   Вверх
feodorv
Дата 11.5.2012, 19:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Alexey91 @  11.5.2012,  18:35 Найти цитируемый пост)
Когда вывожу буфер от recv выводится всякая абракадабра.

Вообще-то должно выводится то, что прислал сервер в ответ на все три send'а (аккумулированные данные).

Цитата(Alexey91 @  11.5.2012,  18:35 Найти цитируемый пост)
Я ожидал увидеть, что мне прислал сервер от последнего send'a

Должно быть от всех трёх send'ов (присланные сервером данные никто не сбрасывает)

Цитата(Alexey91 @  11.5.2012,  18:35 Найти цитируемый пост)
необходимо

В общем случае такой необходимости нет. Но в Вашем лучше всё же дождаться ответа (после каждого send) и проверить на ошибку (а вдруг пароль не подошёл?).

Цитата(boostcoder @  11.5.2012,  19:12 Найти цитируемый пост)
вообще, покажи код отправки user/pass/stat

+1 
А ещё код чтения и вывода того, что получено по recv.


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


Бывалый
*


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

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



Вот код.

Выводится только приветствие яндекса. А еще хотелось бы строки "password please" и "+ОК количество_писем суммарный_размер_писем"

Код

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <iostream>
#include <string>

using namespace std;

void fillArr (char* m, int size)
{
 for(int i=0; i < size; i++) m[i]='\0';
}

void showM (char* msg, int size) // тестировал посимвольный вывод, не обращайте внимания
{
 for(int i=0; i < size; i++) cout << msg[i];
}

int main()
{
 int cl_sock;
 sockaddr_in serv;
 struct hostent *h;

 string buf;
 char msg [200];
 fillArr(msg, 200);

 string com;

 h=gethostbyname("pop.yandex.ru");

 serv.sin_family=AF_INET;
 serv.sin_port=htons(110);
 serv.sin_addr.s_addr=*((unsigned long*)(h->h_addr_list[0])); 
 
 cl_sock=socket(AF_INET,SOCK_STREAM,0);

 if (cl_sock < 0) {    cerr << "cli_sock";    return 1;    }
 

 if ( connect(cl_sock,(sockaddr*)&serv,sizeof(serv)) < 0)                    // apjo
 {
  cerr << "connect";        return 2;    
 }


 com="user [email protected]\r\n";
 send(cl_sock,com.c_str(),com.length(),0);

 com="pass verystrongpass\r\n";
 send(cl_sock,com.c_str(),com.length(),0);

 recv(cl_sock,msg,sizeof(msg),0);
 showM(msg,sizeof(msg));



 cout << endl; 
 return 0;
}


Что выводит telnet:

Код

+OK POP Ya! v1.0.0na@9 umN0AVeSquQ1
user mail
+OK password, please.
pass verystrongpass
+OK 15 7006989


Что выводит прога:
Код

+OK POP Ya! v1.0.0na@9 umN0AVeSquQ1



Однако если после 3-х send вызывать 3 раза recv, то получим, что я хочу:

Код

 recv(cl_sock,msg,sizeof(msg),0);
 showM(msg,sizeof(msg));

 fillArr(msg,sizeof(msg));
 recv(cl_sock,msg,sizeof(msg),0);
 showM(msg,sizeof(msg));

 fillArr(msg,sizeof(msg));
 recv(cl_sock,msg,sizeof(msg),0);
 showM(msg,sizeof(msg));


Код

+OK POP Ya! v1.0.0na@9 umN0AVeSquQ1
+OK password, please.
+OK 15 7006989



По-хорошему для вывода всех 3-х send размера буфера msg хватает (199 символов)  smile 

Это сообщение отредактировал(а) Alexey91 - 12.5.2012, 07:15
PM   Вверх
feodorv
Дата 12.5.2012, 10:33 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Alexey91 @  12.5.2012,  08:01 Найти цитируемый пост)
Однако если после 3-х send вызывать 3 раза recv, то получим, что я хочу:

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


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


Бывалый
*


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

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



Цитата

Видимо, первый recv отрабатывает очень быстро, а поп-сервер ещё не успел прислать ответ на имя пользователя и пароль

Не понял, что ты имеешь ввиду!!!

Еще два моих наблюдения:

1. Похоже еще все это зависит от веб-сервера. 
Например, на яндексе при вызове команды retr, и последующем вызове recv передается:
+ ОК N octets (или ошибка) 
Сообщение

А на mail.ru нужно два раза вызывать recv после retr. 
Сначала вернется + OK N octets, а второй recv уже возвращает сообщение

Как раз эта ситуация очень меня напрягла, потому что я не понимал почему у меня прога висла. Т.к. у меня стояла два recv, то при работе с яндексом, один recv остался "свободным" и ожидал пока от сервера придут пакеты. Похоже нужно использовать неблокирующие сокеты??
2. И еще текст сообщение в теле сообщения у яндекса располагается после строки X-Yandex
А у mail.ru после X-Mras
Почитал RFC 2047, стало понятнее как извлекать заголовки. Но получается так, что нельзя однозначно определить извлечение заголовков для всех серверов, хоть и название заголовков у всех одинаковое.

Мне интересно как почтовые программы с этим все разбираются? Они же умеют работать со всеми серверами. Им только адрес хоста передай, и свой логин и пароль, а они все настроят.

Это сообщение отредактировал(а) Alexey91 - 12.5.2012, 14:51
PM   Вверх
feodorv
Дата 12.5.2012, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Alexey91 @  12.5.2012,  15:48 Найти цитируемый пост)
Не понял, что ты имеешь ввиду!!!

TCP обеспечивает потоковое сообщение между клиентом и сервером. Поток прерывается в трёх случаях: когда клиент или сервер закрыли соединение, когда клиенту или серверу нечего слать друг другу, и когда клиент или сервер медленно отсылают сообщения. Последний случай - наш.

Как работает блокирующий recv? Сначала он смотрит в буфер приёма, присоединённый к сокету, и считывает данные оттуда. Если данных в буфере приёма нет, recv их ждёт. Если данные для чтения в буфере приёма есть (или мы их дождались) и их достаточно для полного заполнения пользовательского буфера, то recv возвращает управление пользователю. А вот если данных мало (они не заполняют пользовательский буфер целиком), recv ждёт непродолжительное время (таймаут ожидания) новой порции данных и лишь потом возвращает управление. То есть recv не знает, придут ли по сокету ещё данные или нет, а возвращает имеющиеся в наличии.

Что получается у нас?
Клиент: send( "command1\r\ncommand2\r\n" )
Сервер: send( "Hello\r\n" ); recv( "command1\r\ncommand2\r\n" ); обрабатываем command1; send( "answer1\r\n" ); обрабатываем command2; send( "answer2\r\n" ); recv( ... );
Клиент: recv( "Hello\r\n" ); таймаут ожидания;

То есть ответы answer1 и answer2 не успевают прочесться клиентским recv - то ли сеть медленно работает, то ли сервер подтормаживает, но истекает таймаут ожидания, и recv возвращает то, что есть в буфере приёма - "Hello". А ответы даже не пытается прочесть... То есть нужно while( recv() ), но тогда нужно указать точный критерий выхода из while (если не было ошибки). Поэтому-то всё-таки лучше всего пошаговый обмен сообщениями...


Цитата(Alexey91 @  12.5.2012,  15:48 Найти цитируемый пост)
1. Похоже еще все это зависит от веб-сервера. 

А то. Если он быстрый, то ответы быстро шлёт. Всё успевает сбуферизироваться в один recv...


Цитата(Alexey91 @  12.5.2012,  15:48 Найти цитируемый пост)
нельзя однозначно определить извлечение заголовков для всех серверов

Почему? Всё стандартизировано, RFC есть. X-заголовки - это заголовки расширения первоначального протокола, но и о них договорились... Поэтому почтовые программы и не теряются при обмене с поп-сервером...


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


Бывалый
*


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

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



feodorv, спасибо, все очень подробно написано, теперь я понял ;)

По поводу заголовков. Есть кусок сообщения от mail.ru

Код

----ALT--zhor8Gn41336708377
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: base64

text
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64

text
----ALT--zhor8Gn41336708377--

.



А вот от yandex'a

Код

Content-Type: text/plain; charset="KOI8-R"; format="flowed"
Content-Transfer-Encoding: 8bit
Return-Path: [email protected]
X-Yandex-Forward: add32a4340ab0ce573

text
.



У других серверов также свои представления.
Заголовки да, они определены стандарты, присутствуют у всех сообщений.

Вот как здесь однозначно вырезать нужный текст?

Я имею ввиду типа string.substr(begin_pos,length)

Это сообщение отредактировал(а) Alexey91 - 12.5.2012, 17:29
PM   Вверх
feodorv
Дата 12.5.2012, 18:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Alexey91 @  12.5.2012,  18:21 Найти цитируемый пост)
Вот как здесь однозначно вырезать нужный текст?

Для mail.ru Вы не привели предшествующих заголовков сообщения, начиная с "From ...". А ведь там задан boundary. А для Яндекса не задан.
То есть одним телом сообщения обойтись не удастся. Нужны заголовки сообщения. И уже исходя из них решать, как обрабатывать тело сообщения... Ничего там сложного нет...


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


 




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


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

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