Форум программистов CODEBY.NET Хостинг в Беларуси — Active Technologies

Разработка бизнес сайтов

Нужны клиенты? Тогда сюда быстрее...
X   Сообщение сайта
(Сообщение закроется через 2 секунды)

Здравствуйте, гость ( Вход | Регистрация )




> Mra протокол.помогите разобраться
ReindeeR
Вставить ник
сообщение 3:04:2008, 12:52
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


Вы уж извините,что так сразу,с такими вопросами тупыми врываюсь)

Решил попрактиковаться в работе с сетью и с сокетами,
выбор мой пал на создание примитивного mail.ru агента,
консольное приложение,которое может хотя бы могло законнектится к серверу,
и пройти авторизацию юзера.Сейчас опишу,как и что делаю.
Сначала подключаю winsock.2 и подгружаю библиотеку ws2_32.Lib
адрес и порт,по которому коннектится
Код
#define PORT 2042
#define SERVERADDR "mrim.mail.ru"

Функцией WSAStartup() подготавливаю для работы winsock2
Создаю сокет,
Код
my_sock=socket(AF_INET,SOCK_STREAM,0);

заполняю структуру sockaddr_in
Код
sockaddr_in dest_addr;
dest_addr.sin_family=AF_INET;
dest_addr.sin_port=htons(PORT);
HOSTENT *hst;

далее преобразуем адрес
Код
hst=gethostbyname ( SERVERADDR );
( ( unsigned long   * ) &dest_addr.sin_addr ) [ 0 ] =( ( unsigned long    ** ) hst->h_addr_list ) [ 0 ] [ 0 ];

сам коннект
Код
connect(my_sock,(sockaddr*) &dest_addr,sizeof(dest_addr));

Вот отсюда и начинаются все непонятки,что делать,как отсылать и принимать.

вот описание протокола
http://agent.mail.ru/protocol.html

Все проблемы начались с непонятного инклюда,в файле,который выложен в описании протокола,
Код
#include

и все,а что собственно нужно подключать??,не сказано=(
ну я удалил эту строчку за ненадобностьюsmile.gif

идем далее,сказано,в том же описании,что
"После установки tcp-соединения клиент обязан сразу послать MRIM_CS_HELLO"
Вот и главная проблема.Как отправлять,прнимать,и вообще как их создавать,эти пакеты?
Код
Заголовок пакета
{
    u_long      magic; // Magic
    u_long      proto; // Версия протокола
    u_long      seq; // Sequence
    u_long      msg; // Тип пакета
    u_long      dlen;  // Длина данных
    u_long from; // Адрес отправителя
    u_long fromport; // Порт отправителя
    u_char reserved[16]; // Зарезервировано
}

По порядку,
magic,это мне понятно
в файле proto.h есть константа
Код
#define CS_MAGIC    0xDEADBEEF


версия протокола,тоже понятно откуда брать
Код
#define PROTO_VERSION_MAJOR     1
#define PROTO_VERSION_MINOR     7
#define PROTO_VERSION ((((u_long)(PROTO_VERSION_MAJOR))<<16)|(u_long)(PROTO_VERSION_MINOR))


Sequence,а вот что это такое,я так и не понял.
тип пакета,как я понял,тут и надо указывать MRIM_CS_HELLO
Адрес и порт отправителя,тут что указывать?

Ладно,допустим я разобрался что и где писать,
а как называть пакет?
из файла
Код
typedef struct mrim_packet_header_t
{
    u_long      magic; // Magic
    u_long      proto; // Версия протокола
    u_long      seq; // Sequence
    u_long      msg; // Тип пакета
    u_long      dlen;  // Длина данных
    u_long from; // Адрес отправителя
    u_long fromport; // Порт отправителя
    u_char reserved[16]; // Зарезервировано
}
mrim_packet_header_t;

вот тут я окончательно запутался.
mrim_packet_header_t это тип структуры,и имя пакета одновременно?
Код
int send(SOCKET s,char* buf,int len,int flags);

компилятор ругается,при попытке отправить пакет,
приводить его к типу char* и отправлять?или как быть?
та же история и при приеме данных.

Ну вот,все сказал вроде,что непонятно.
Если вы дочитали до конца весь этот бред,и не поленились посмотреть описание
протокола,огромнейшая просьба,хоть как-то помочьrolleyes.gif
Подняться вверх 
 
Сообщение #1
2 страниц V   1 2 >  
Новая тема 
Ответов (1 - 29)
Yason
Вставить ник
сообщение 15:04:2008, 03:08
Цитата Ответить 


Продвинутый
**

Группа: Программист
Сообщений: 134
Регистрация: 27:02:2004
Пользователь №: 296



Репутация: - 6 +


Ничего себе тренировочная задачка! wink.gif

Судя по всему,
Код
{
    u_long    magic;    //волшебный ключ, указывающий на то, что это действительно пакет MMP
    u_long    proto;  //версия MMP, поддерживаемая отправителем пакета
    u_long    seq;  //номер отправляемой команды в текущем соединении. Ответ на команду должен иметь тот же номер, что и сама команда.
    u_long    msg;  //тип пакета, номер команды и/или ответа
    u_long    dlen;  //длина данных пакета (без учета заголовка)
    u_long    from;  //ip (в inet_aton() формате) с которого установлено соединение
    u_long    fromport;  //порт (в inet_aton() формате) с которого установлено соединение
    u_char    reserved[16];
}

MRIM_CS_HELLO, как я понял, нужно прописать в seq. Затем отправляешь этот пакет (по сути, только заголовок, ибо в MRIM_CS_HELLO доп. данные не предполагаются) (да, явно приведя к типу char*) и ждёшь, когда тебе придёт ответ от сервера в виде заголовка (с msg=MRIM_CS_HELLO_ACK) и параметров (структура mrim_connection_params_t. К слову, это только тип структуры, а не имя пакета). Ну и дальше, как там описано.

P.S. Протокол этот впервые вижу, так что могу в чём-то заблуждаться.

Сообщение отредактировал Yason - 15:04:2008, 03:09
Подняться вверх 
 
Сообщение #2
ReindeeR
Вставить ник
сообщение 15:04:2008, 12:57
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


не,seq это просто номер команды,в ответе он должен быть таким же,короче это не очень важный параметр))
MRIM_CS_HELLO надо отправлять первым,указывая в msg.
отправить у меня получается,а вот в ответ приходит чет непонятное.
И потом как мне узнать,что пришло?
Если принять пакет с msg=MRIM_CS_HELLO_ACK,
то как принять mrim_connection_params_t ?
это же две разные структуры,и как мне они придут в одном ответе? huh.gif
короче,как было ничего непонятно,так все и осталось)
лан,ща буду мучаться
Подняться вверх 
 
Сообщение #3
Yason
Вставить ник
сообщение 16:04:2008, 01:22
Цитата Ответить 


Продвинутый
**

Группа: Программист
Сообщений: 134
Регистрация: 27:02:2004
Пользователь №: 296



Репутация: - 6 +


ReindeeR
Каждый пакет состоит из заголовка (mrim_packet_header_t) и следующих за ними данных (зависят от команды, для MRIM_CS_HELLO_ACK - mrim_connection_params_t; для некоторых команд, типа MRIM_CS_HELLO - отсутствуют). Размер передаваемых данных нужно указывать в mrim_packet_header_t.dlen. Ну, это, я думаю, и так понятно smile.gif
А ответ можно (и нужно) считывать за несколько приёмов. Сначала заголовок размером sizeof(mrim_packet_header_t), затем по считанному заголовку определяешь, какого типа данные ожидаются, создаёшь буфер соответствующего типа, и считываешь из сокета в него остаток пакета.

Как узнать что "вам пакет от сервера" - либо тупо ждать после отправки запроса, либо тоже самое, только умно - в отдельном потоке (thread) с контролем таймаута.
Подняться вверх 
 
Сообщение #4
ReindeeR
Вставить ник
сообщение 16:04:2008, 03:42
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


в ответ приходит какая-то фигня размеров в 19 байтов. huh.gif
зы.причем один раз

ап.
mrim_connection_params_t 4 байта,
можно попробовать вынять эти 4 байта с начала или конца принятых 19 wacko.gif

зы.
а как это сделать? blink.gif

Сообщение отредактировал ReindeeR - 16:04:2008, 03:52
Подняться вверх 
 
Сообщение #5
Yason
Вставить ник
сообщение 16:04:2008, 13:18
Цитата Ответить 


Продвинутый
**

Группа: Программист
Сообщений: 134
Регистрация: 27:02:2004
Пользователь №: 296



Репутация: - 6 +


ReindeeR
Могу поспорить, что эта фигня складывается в циферки типа "194.186.55.27:2041" wink.gif
Цитата
Рекомендованный для соединения сервер в любой момент времени можно получить в текстовом формате ip:port по адресу mrim.mail.ru:2042 и mrim.mail.ru:443

Зайди браузером на http://mrim.mail.ru:2042, и воочию увидишь, что именно ты получаешь smile.gif

P.S. Поздравляю, значит приём-передача уже как-то работают!
Подняться вверх 
 
Сообщение #6
ReindeeR
Вставить ник
сообщение 16:04:2008, 13:42
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


Цитата(Yason @ 16:04:2008, 16:18 ) *
ReindeeR
Могу поспорить, что эта фигня складывается в циферки типа "194.186.55.27:2041" wink.gif

Зайди браузером на http://mrim.mail.ru:2042, и воочию увидишь, что именно ты получаешь smile.gif

P.S. Поздравляю, значит приём-передача уже как-то работают!

ааааа
я как дятел больше 10 дней пытаюсь достучаться по этому адресу и выпытать ответ.
мда..внимательнее читать надо unsure.gif
щас буду пробовать коннектиться на получаемый адрес rolleyes.gif ))
Подняться вверх 
 
Сообщение #7
ReindeeR
Вставить ник
сообщение 16:04:2008, 22:29
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


Новая проблемка))
не получается установить коннект с сервером.
Точнее получается,только не совсем правильно.
полученный адрес,по которому нужно соединятся с сервером,
находится в переменной IPaddr в формате "194.186.55.17:2041".
разделяю их с помощью strtok
Код
ip=strtok(IPaddr,":");
port=strtok('\0',":");

далее засовываю в структуру sockaddr_in dest_addr
Код
dest_addr.sin_family=AF_INET;
dest_addr.sin_addr.s_addr=inet_addr(ip);
dest_addr.sin_port=htons((u_short)port);

ну и соединяюсь connect(my_sock,(SOCKADDR*) &dest_addr,sizeof(dest_addr));
ну и собственно ничего не соединяется.
еще при компиляции выскакивает варнинг
cast from pointer to integer of different size
ругается на строчку,где функция htons()
в чем опять проблема?и как собственно ее решить?
пока сделал так,посмотрел один из адресов,которые выдаются
и объявил константами,
#define,не знаю как это правильно называется))
Подняться вверх 
 
Сообщение #8
Yason
Вставить ник
сообщение 17:04:2008, 01:11
Цитата Ответить 


Продвинутый
**

Группа: Программист
Сообщений: 134
Регистрация: 27:02:2004
Пользователь №: 296



Репутация: - 6 +


Цитата(ReindeeR @ 17:04:2008 - 02:29) *
cast from pointer to integer of different size
ругается на строчку,где функция htons()

Ну, ругается, очевидно, потому, что не желает char* с номером порта переводить в u_short путём приведения типов.
Видимо, просит atoi(port) smile.gif
Подняться вверх 
 
Сообщение #9
ReindeeR
Вставить ник
сообщение 17:04:2008, 03:16
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


С портом разобрался))
теперь проблема с приемом данных.
цитата из описания.
Цитата
После установки tcp-соединения клиент обязан сразу послать MRIM_CS_HELLO, дождаться MRIM_CS_HELLO_ACK

hello отправляю,а в ответ тишина...
собственно сделал вывод,что пакет с MRIM_CS_HELLO у меня отправляется криво,раз ответа нет.
делаю так:

Код
mrim_packet_header_t packHello;
packHello.magic=CS_MAGIC;      //формирование пакета
packHello.proto=PROTO_VERSION;
packHello.seq=i;
packHello.msg=MRIM_CS_HELLO;
packHello.dlen=sizeof(mrim_packet_header_t);
packHello.from=0;
packHello.fromport=0;
send(my_sock,(char*)packHello,bufsize,0);//отправляется 44 байта,как и должно по идее.

//далее попытка принять пакет.
    do
    {
        char *buffer;
        int iResult=recv(mySock,buffer,bufsize,0);
        if(iResult>0)
            cout << "Размер полученных данных="<< iResult  << endl;
        else if(iResult==0)
            cout << "Прием данных завершен.\n";
        else
            cout << WSAGetLastError() <<endl;
    }while(iResult>0);

при попытке принять данные все висит секунд 50,ничего не принимая,
а потом "Прием данных завершен." unsure.gif
Подняться вверх 
 
Сообщение #10
Yason
Вставить ник
сообщение 17:04:2008, 12:29
Цитата Ответить 


Продвинутый
**

Группа: Программист
Сообщений: 134
Регистрация: 27:02:2004
Пользователь №: 296



Репутация: - 6 +


Код
packHello.from=0;
packHello.fromport=0;

По идее, там должны быть IP и порт отправителя (т.е. клиента).


Код
send(my_sock,(char*)packHello,bufsize,0);

Если мне не изменяет склероз, должно быть
Код
send(my_sock,(char*)&packHello,bufsize,0);


Далее, учитывая, что "длина данных пакета (без учета заголовка)"
Код
packHello.dlen=0;


И ответ, как мне кажется, было бы логичнее ждать в таком виде:
Код
mrim_packet_header_t buffer;
int iResult=recv(mySock, (char*)&buffer, bufsize, 0);

Подняться вверх 
 
Сообщение #11
ReindeeR
Вставить ник
сообщение 17:04:2008, 14:46
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


Цитата(Yason @ 17:04:2008 - 16:29) *
По идее, там должны быть IP и порт отправителя (т.е. клиента).

IP указывать не надо,а вот порт оказалось обязательно,просто у кого не спрашивал,все говорили типа устанавливается все в ноль mad.gif

ага,поставил ноль.
Цитата(Yason @ 17:04:2008 - 16:29) *
Далее, учитывая, что "длина данных пакета (без учета заголовка)"
packHello.dlen=0;

ага,поставил ноль.
Ну вот после этих исправлений данные пришли.
В размере 48 байтов.
44 байта заголовок,и 4 байта данные,mrim_connection_params_t
Цитата(Yason @ 17:04:2008 - 16:29) *
send(my_sock,(char*)&packHello,bufsize,0);

опечатался.все так и есть.
Цитата(Yason @ 17:04:2008 - 16:29) *
И ответ, как мне кажется, было бы логичнее ждать в таком виде:

обычно так и принимал,просто экспериментировал smile.gif
ну вот,данные получены,проверил,все правильно,msg==MRIM_CS_HELLO_ACK
dlen==4 байта,что и ожидалось.
Ну и очередной вопрос,как мне достать эти четыре байта,mrim_connection_params_t.ping_period?

Сообщение отредактировал ReindeeR - 17:04:2008, 14:47
Подняться вверх 
 
Сообщение #12
Yason
Вставить ник
сообщение 17:04:2008, 15:01
Цитата Ответить 


Продвинутый
**

Группа: Программист
Сообщений: 134
Регистрация: 27:02:2004
Пользователь №: 296



Репутация: - 6 +


Так а в чём проблема?
Код
mrim_packet_header_t header;
int iResult=recv(mySock, (char*)&header, sizeof(header), 0);
mrim_connection_params_t params;
iResult=recv(mySock, (char*)&params, sizeof(params), 0);
Подняться вверх 
 
Сообщение #13
ReindeeR
Вставить ник
сообщение 17:04:2008, 15:31
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


не знал,что так можно. unsure.gif
интервал получил,30 сек).
далее авторизация юзверя.
Цитата
Пакет: Авторизация

Имя пакета: MRIM_CS_LOGIN2
Тип пакета: cs
Параметры:

LPS ## login ## email авторизующегося пользователя
LPS ## password ## пароль
UL ## status ## статус (см. MRIM_CS_CHANGE_STATUS)
LPS ## user_agent ## текстовое описание клиента пользователя, например "Mail.Ru Miranda Plugin v 1.0"

как мне эти данные присоединть к пакету?

и еще.
как отправлять пакет c MRIM_CS_PING каждые 30 секунд?
в winAPI понятно,таймер и все.
а как в консоли это сделать?
Подняться вверх 
 
Сообщение #14
Yason
Вставить ник
сообщение 17:04:2008, 21:40
Цитата Ответить 


Продвинутый
**

Группа: Программист
Сообщений: 134
Регистрация: 27:02:2004
Пользователь №: 296



Репутация: - 6 +


Цитата(ReindeeR @ 17:04:2008 - 18:31) *
как мне эти данные присоединть к пакету?

Аналогично чтению - в несколько этапов. Сначала отправляешь заголовок, потом длину логина, потом сам логин, потом длину пароля, и т.д. Разумеется, dlen должен быть равен суммарной длине данных (исключая заголовок).

Цитата(ReindeeR @ 17:04:2008 - 18:31) *
как отправлять пакет c MRIM_CS_PING каждые 30 секунд?

Либо SetTimer(NULL, 0, 30000, SendPing()), либо создать отдельный поток и в нём
Код
while (!quit) {
    SendPing();
    Sleep(30000);
}

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

Сообщение отредактировал Yason - 17:04:2008, 21:43
Подняться вверх 
 
Сообщение #15
ReindeeR
Вставить ник
сообщение 18:04:2008, 01:28
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


ыыы,авторизировался cool.gif )))
щас буду пробовать таймер установить.
Потоки=темный лес для меня пока что.

зы.
как синхронизировать все это,чтобы косяков не было? wacko.gif

ап.
Таймер использовать не получилось,так как он сразу убивается у меня.
Всмысле запускаю таймер,выполняется только первый раз при запуске,
а потом программа завершается,и абсолютно пофиг,что там таймер запущен.

ну а поток создать у меня тем более не получается.
ошибок вылезает хз скока.
Мне надо передать в функцию потока сокет и интервал пинга.
А если учитывать то,что про потоки я прочитал несколько часов назад,
для меня эта задача вообще невыполнимая ph34r.gif

Сообщение отредактировал ReindeeR - 18:04:2008, 04:08
Подняться вверх 
 
Сообщение #16
Yason
Вставить ник
сообщение 18:04:2008, 13:56
Цитата Ответить 


Продвинутый
**

Группа: Программист
Сообщений: 134
Регистрация: 27:02:2004
Пользователь №: 296



Репутация: - 6 +


Цитата(ReindeeR @ 18:04:2008 - 01:28) *
Всмысле запускаю таймер,выполняется только первый раз при запуске,
а потом программа завершается,и абсолютно пофиг,что там таймер запущен.

Ну, программа и не должна ждать таймер, поэтому её нужно зациклить. А учитывая, что для нормальной работы таймера "you need to dispatch messages in the calling thread" © WinAPI, зациклить программу можно как-нибудь так:
Код
/* Acquire and dispatch messages until a WM_QUIT message is received. */
while (GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}


Цитата(ReindeeR @ 18:04:2008 - 01:28) *
как синхронизировать все это,чтобы косяков не было?

После вдумчивого чтения хелпа по SetTimer, оказалось, что таймер работает через сообщения в основном потоке, поэтому синхронизировать его не нужно.
При многопоточности, конечно, всё не так радужно smile.gif
Подняться вверх 
 
Сообщение #17
ReindeeR
Вставить ник
сообщение 18:04:2008, 14:41
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


дело в том,что у меня приложение консольное,
цикл обработки сообщений никуда не запехаешь))
Подняться вверх 
 
Сообщение #18
Yason
Вставить ник
сообщение 18:04:2008, 15:55
Цитата Ответить 


Продвинутый
**

Группа: Программист
Сообщений: 134
Регистрация: 27:02:2004
Пользователь №: 296



Репутация: - 6 +


Ну не знаю, не знаю... Это - работает smile.gif
CODE
int CALLBACK tick()
{
cout<<"tick\n";
}

int main(int argc, char* argv[])
{
SetTimer(NULL, 0, 1000, tick);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Подняться вверх 
 
Сообщение #19
ReindeeR
Вставить ник
сообщение 18:04:2008, 18:41
Цитата Ответить 


Новенький
*

Группа: Программист
Сообщений: 39
Регистрация: 3:04:2008
Пользователь №: 16 361



Репутация: - 1 +


ну тогда как передать мне в функцию tick() параметры?))

ап.
извиняюсь,как обычно туплю smile.gif

Цитата(Yason @ 18:04:2008, 19:55 ) *
Ну не знаю, не знаю... Это - работает smile.gif
int CALLBACK tick()
{
cout<<"tick\n";
}

на такую функцию компилятор матерился.
пришлось городить вот так
Код
void CALLBACK tick(HWND ccc,UINT iii,UINT aaa,DWORD bbb)


Код
mrim_packet_header_t packPing;
    packPing.magic=CS_MAGIC;
    packPing.proto=PROTO_VERSION;
    packPing.seq=0;
    packPing.msg=MRIM_CS_PING;
    packPing.dlen=0;
    packPing.from=0;
    packPing.fromport=2041;
    int iResult=send(my_sock,(char*)&packPing,sizeof(packPing),0);

новая проблема.
при отсылке такого пакета сразу же обрывается соединение.

Сообщение отредактировал ReindeeR - 18:04:2008, 18:09
Подняться вверх 
 
Сообщение #20
Yason
Вставить ник
сообщение 18:04:2008, 21:47
Цитата Ответить 


Продвинутый
**

Группа: Программист
Сообщений: 134
Регистрация: 27:02:2004
Пользователь №: 296