Помощник
Здравствуйте, гость ( Вход | Регистрация )
|
|
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 и все,а что собственно нужно подключать??,не сказано=( ну я удалил эту строчку за ненадобностью идем далее,сказано,в том же описании,что "После установки 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* и отправлять?или как быть? та же история и при приеме данных. Ну вот,все сказал вроде,что непонятно. Если вы дочитали до конца весь этот бред,и не поленились посмотреть описание протокола,огромнейшая просьба,хоть как-то помочь |
|
Сообщение
#1
|
|
![]() |
|
|
15:04:2008, 03:08
|
|
Продвинутый ![]() ![]() Группа: Программист Сообщений: 134 Регистрация: 27:02:2004 Пользователь №: 296 Репутация: 6
|
Ничего себе тренировочная задачка!
Судя по всему, Код { 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
|
|
|
|
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 ? это же две разные структуры,и как мне они придут в одном ответе? короче,как было ничего непонятно,так все и осталось) лан,ща буду мучаться |
|
Сообщение
#3
|
|
|
|
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. Ну, это, я думаю, и так понятно А ответ можно (и нужно) считывать за несколько приёмов. Сначала заголовок размером sizeof(mrim_packet_header_t), затем по считанному заголовку определяешь, какого типа данные ожидаются, создаёшь буфер соответствующего типа, и считываешь из сокета в него остаток пакета. Как узнать что "вам пакет от сервера" - либо тупо ждать после отправки запроса, либо тоже самое, только умно - в отдельном потоке (thread) с контролем таймаута. |
|
Сообщение
#4
|
|
|
|
16:04:2008, 03:42
|
|
Новенький ![]() Группа: Программист Сообщений: 39 Регистрация: 3:04:2008 Пользователь №: 16 361 Репутация: 1
|
в ответ приходит какая-то фигня размеров в 19 байтов.
зы.причем один раз ап. mrim_connection_params_t 4 байта, можно попробовать вынять эти 4 байта с начала или конца принятых 19 зы. а как это сделать? Сообщение отредактировал ReindeeR - 16:04:2008, 03:52 |
|
Сообщение
#5
|
|
|
|
16:04:2008, 13:18
|
|
Продвинутый ![]() ![]() Группа: Программист Сообщений: 134 Регистрация: 27:02:2004 Пользователь №: 296 Репутация: 6
|
ReindeeR
Могу поспорить, что эта фигня складывается в циферки типа "194.186.55.27:2041" Цитата Рекомендованный для соединения сервер в любой момент времени можно получить в текстовом формате ip:port по адресу mrim.mail.ru:2042 и mrim.mail.ru:443 Зайди браузером на http://mrim.mail.ru:2042, и воочию увидишь, что именно ты получаешь P.S. Поздравляю, значит приём-передача уже как-то работают! |
|
Сообщение
#6
|
|
|
|
16:04:2008, 13:42
|
|
Новенький ![]() Группа: Программист Сообщений: 39 Регистрация: 3:04:2008 Пользователь №: 16 361 Репутация: 1
|
ReindeeR Могу поспорить, что эта фигня складывается в циферки типа "194.186.55.27:2041" Зайди браузером на http://mrim.mail.ru:2042, и воочию увидишь, что именно ты получаешь P.S. Поздравляю, значит приём-передача уже как-то работают! ааааа я как дятел больше 10 дней пытаюсь достучаться по этому адресу и выпытать ответ. мда..внимательнее читать надо щас буду пробовать коннектиться на получаемый адрес |
|
Сообщение
#7
|
|
|
|
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
|
|
|
|
17:04:2008, 01:11
|
|
Продвинутый ![]() ![]() Группа: Программист Сообщений: 134 Регистрация: 27:02:2004 Пользователь №: 296 Репутация: 6
|
|
|
Сообщение
#9
|
|
|
|
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,ничего не принимая, а потом "Прием данных завершен." |
|
Сообщение
#10
|
|
|
|
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
|
|
|
|
17:04:2008, 14:46
|
|
Новенький ![]() Группа: Программист Сообщений: 39 Регистрация: 3:04:2008 Пользователь №: 16 361 Репутация: 1
|
По идее, там должны быть IP и порт отправителя (т.е. клиента). IP указывать не надо,а вот порт оказалось обязательно,просто у кого не спрашивал,все говорили типа устанавливается все в ноль ага,поставил ноль. Далее, учитывая, что "длина данных пакета (без учета заголовка)" packHello.dlen=0; ага,поставил ноль. Ну вот после этих исправлений данные пришли. В размере 48 байтов. 44 байта заголовок,и 4 байта данные,mrim_connection_params_t send(my_sock,(char*)&packHello,bufsize,0); опечатался.все так и есть. И ответ, как мне кажется, было бы логичнее ждать в таком виде: обычно так и принимал,просто экспериментировал ну вот,данные получены,проверил,все правильно,msg==MRIM_CS_HELLO_ACK dlen==4 байта,что и ожидалось. Ну и очередной вопрос,как мне достать эти четыре байта,mrim_connection_params_t.ping_period? Сообщение отредактировал ReindeeR - 17:04:2008, 14:47 |
|
Сообщение
#12
|
|
|
|
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*)¶ms, sizeof(params), 0); |
|
Сообщение
#13
|
|
|
|
17:04:2008, 15:31
|
|
Новенький ![]() Группа: Программист Сообщений: 39 Регистрация: 3:04:2008 Пользователь №: 16 361 Репутация: 1
|
не знал,что так можно.
интервал получил,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
|
|
|
|
17:04:2008, 21:40
|
|
Продвинутый ![]() ![]() Группа: Программист Сообщений: 134 Регистрация: 27:02:2004 Пользователь №: 296 Репутация: 6
|
как мне эти данные присоединть к пакету? Аналогично чтению - в несколько этапов. Сначала отправляешь заголовок, потом длину логина, потом сам логин, потом длину пароля, и т.д. Разумеется, dlen должен быть равен суммарной длине данных (исключая заголовок). как отправлять пакет 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
|
|
|
|
18:04:2008, 01:28
|
|
Новенький ![]() Группа: Программист Сообщений: 39 Регистрация: 3:04:2008 Пользователь №: 16 361 Репутация: 1
|
ыыы,авторизировался
щас буду пробовать таймер установить. Потоки=темный лес для меня пока что. зы. как синхронизировать все это,чтобы косяков не было? ап. Таймер использовать не получилось,так как он сразу убивается у меня. Всмысле запускаю таймер,выполняется только первый раз при запуске, а потом программа завершается,и абсолютно пофиг,что там таймер запущен. ну а поток создать у меня тем более не получается. ошибок вылезает хз скока. Мне надо передать в функцию потока сокет и интервал пинга. А если учитывать то,что про потоки я прочитал несколько часов назад, для меня эта задача вообще невыполнимая Сообщение отредактировал ReindeeR - 18:04:2008, 04:08 |
|
Сообщение
#16
|
|
|
|
18:04:2008, 13:56
|
|
Продвинутый ![]() ![]() Группа: Программист Сообщений: 134 Регистрация: 27:02:2004 Пользователь №: 296 Репутация: 6
|
Всмысле запускаю таймер,выполняется только первый раз при запуске, а потом программа завершается,и абсолютно пофиг,что там таймер запущен. Ну, программа и не должна ждать таймер, поэтому её нужно зациклить. А учитывая, что для нормальной работы таймера "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); } как синхронизировать все это,чтобы косяков не было? После вдумчивого чтения хелпа по SetTimer, оказалось, что таймер работает через сообщения в основном потоке, поэтому синхронизировать его не нужно. При многопоточности, конечно, всё не так радужно |
|
Сообщение
#17
|
|
|
|
18:04:2008, 14:41
|
|
Новенький ![]() Группа: Программист Сообщений: 39 Регистрация: 3:04:2008 Пользователь №: 16 361 Репутация: 1
|
дело в том,что у меня приложение консольное,
цикл обработки сообщений никуда не запехаешь)) |
|
Сообщение
#18
|
|
|
|
18:04:2008, 15:55
|
|
Продвинутый ![]() ![]() Группа: Программист Сообщений: 134 Регистрация: 27:02:2004 Пользователь №: 296 Репутация: 6
|
Ну не знаю, не знаю... Это - работает
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
|
|
|
|
18:04:2008, 18:41
|
|
Новенький ![]() Группа: Программист Сообщений: 39 Регистрация: 3:04:2008 Пользователь №: 16 361 Репутация: 1
|
ну тогда как передать мне в функцию tick() параметры?))
ап. извиняюсь,как обычно туплю Ну не знаю, не знаю... Это - работает 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
|
|
|
|
18:04:2008, 21:47
|
|
Продвинутый ![]() ![]() Группа: Программист Сообщений: 134 Регистрация: 27:02:2004 Пользователь №: 296 |