Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > Расшифровать ответ сервера


Автор: leporel 26.2.2010, 19:54
Посылаю запрос

 
Код
const Byte Qwerty[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x53, 0x6F, 0x75, 0x72,
0x63, 0x65, 0x20, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x00};

 if (IdUDPClient1->Active)
      IdUDPClient1->Active = false;
   IdUDPClient1->Host = "85.21.79.33";
   IdUDPClient1->Port =  27017;
   IdUDPClient1->Active = true;
   char Answer[256];

   IdUDPClient1->SendBuffer(RawToBytes(Qwerty, sizeof(Qwerty)));
   try
   {
      Sysutils::TBytes ReceiveBuff;
      ReceiveBuff.set_length(256);
      IdUDPClient1->ReceiveBuffer(ReceiveBuff, Timeout);

   }
   catch(EIdSocketError& e)
   {
      return 0;
   };


Ответ получается в ReceiveBuff
Как вывести его по http://developer.valvesoftware.com/wiki/Server_Queries#Reply_format_3?


Я не знаю как в Memo добавлять в одну и туже строку символы, но все равно делаю вот так

Код
for(int i=0; i<256; i++)
       Memo1->Lines->Add((char&)ReceiveBuff[i]);


И в Memo только данные типа "String" показывает.

Автор: XPyCT 27.2.2010, 00:44
ну предположим,  подготовить для мемо можно попытаться так

Код

#include <stdio.h>


//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int len_ch=14;
char ** tmp = new char *[len_ch];
char ** buf = new char *[len_ch];
 for(int i=0; i < len_ch; i++)
 {
   buf[i] = new char[20];
   tmp[i]= "1235,3265,7458";
   sprintf(buf[i],tmp[i],i);
 }
  String str = tmp[0];
}
//---------------------------------------------------------------------------


Технику применения думаю разрулите

Автор: mrbrooks 27.2.2010, 08:48
Цитата(leporel @  26.2.2010,  19:54 Найти цитируемый пост)
Как вывести его по кускам?

что бы разложить буфер по частям - необходимо представлять, что отвечает сервер. То бишь знать протокол обмена.

Автор: leporel 27.2.2010, 11:25
mrbrooks, http://developer.valvesoftware.com/wiki/Server_Queries#Reply_format_3

Автор: mrbrooks 27.2.2010, 11:48
leporel, ок. Ответ ты получаешь в виде String. Теперь, как я понимаю, ты хочешь разложить строку по байтам?  Если так то тебе необходимо либо ее перевести в буфер char методом c_str() строки, либо циклом по строке начиная с индекса 1, а не 0.

т.е.
Код

for(int i=1; i<ReceiveBuff.Length; i++)
       Memo1->Lines->Add(ReceiveBuff[i]);


Так ты разложишь буфер по символам. 

Автор: leporel 27.2.2010, 12:11
Цитата

Так ты разложишь буфер по символам. 

Так он цифры выводит, а если поставить Memo1->Lines->Add((char)ReceiveBuff[i]); буквы выводит.

Попытался что-то сделать с тем что хруст предложил

Код

int len_ch=256;
    String str;
    char tmp;
    char ** buf = new char *[len_ch];
     for(int i=0; i < len_ch; i++)
     {
      buf[i] = new char[256];
      tmp = (char)ReceiveBuff[i];
      sprintf(buf[i],&tmp,i);
      str = str + buf[i];
     }
  Memo1->Lines->Add(str); 


Выводит теже самые символы но в одну строчку хоть. 

НО! символами показаны только переменные стринг (тоесть Server Name, Map, Game Directory и т.д) все остальные данные "byte" и "short" или не отображаются, или иероглифы. 
byte он только в самом начале отображает большую букву I (Type   byte   Should be equal to 'I' (0x49))

ЗЫ: Посмотрел что он цифрами выводит, и получается переменные типа byte он правильно показывает. И как понять где стринг выводить, а где цифру?

Автор: vikaz 27.2.2010, 12:22
Камрад, наверное надо:   i<=ReceiveBuff.Length, иначе одного символа не досчитаемся!


Цитата(leporel @  27.2.2010,  14:11 Найти цитируемый пост)
ЗЫ: Посмотрел что он цифрами выводит, и получаеться переменные типа byte он правильно показывает. И как понять где стринг выводить, а где цифру?

Создай структуру которая будет полностью описывать ответ сервера и разложи строку в структуру.

Автор: mrbrooks 27.2.2010, 12:41
Цитата(leporel @  27.2.2010,  12:11 Найти цитируемый пост)
И как понять где стринг выводить, а где цифру?

вот для этого и нужно знать протокол обмена. какой то кусок буфера - слово, какой то - цифра. 
vikaz сто раз прав. надо создать свою структуру - которая описывает принимаемый буфер в соответствие с протоколом обмена.

Автор: leporel 27.2.2010, 12:46
Цитата

разложи строку в структуру.


как?

Код

      if(((int)*buf[i]>=192 && (int)*buf[i]<=255) || ((int)*buf[i]>=65 && (int)*buf[i]<=122))
      str = str + buf[i];
      else
      str = str + (int)*buf[i] + " ";


этим мои знания заканчиваются 


PS
Цитата

какой то кусок буфера - слово, какой то - цифра. 


Можно пример?

Автор: mrbrooks 27.2.2010, 13:52
Цитата(leporel @  27.2.2010,  12:46 Найти цитируемый пост)
как?

да вот же она 
Цитата

Type   byte   Should be equal to 'I' (0x49)
Version  byte  Network version. 0x07 is the current Steam version. Goldsource games will return 48 (0x30), also refered to as protocol version.
Server Name  string  The Source server's name, eg: "Recoil NZ CS Server #1"
Map  string  The current map being played, eg: "de_dust"
Game Directory  string  The name of the folder containing the game files, eg: "cstrike"
Game Description  string  A friendly string name for the game type, eg: "Counter Strike: Source"
AppID  short  Steam Application ID
Number of players  byte  The number of players currently on the server
Maximum players  byte  Maximum allowed players for the server
Number of bots  byte  Number of bot players currently on the server
Dedicated  byte  'l' for listen, 'd' for dedicated, 'p' for SourceTV
OS  byte  Host operating system. 'l' for Linux, 'w' for Windows
Password  byte  If set to 0x01, a password is required to join this server
Secure  byte  if set to 0x01, this server is VAC secured
Game Version  string  The version of the game, eg: "1.0.0.22"
Extra Data Flag (EDF)  byte  if present this specifies which additional data fields will be included
if ( EDF & 0x80 )  short  The server's game port # is included
if ( EDF & 0x40 )  short string  The spectator port # and then the spectator server name are included
if ( EDF & 0x20 )  string  The game tag data string for the server is included [future use] 


все прекрасно расписано. 

описываешь ее, затем копируешь в нее полученный буфер тем же memcpy.

Автор: leporel 27.2.2010, 14:56
Извините меня, но  smile 
memcpy - как я понял, копирует из чего то в другое, с указанным количество байтов, я не знаю как это реализовать...

Автор: leporel 2.3.2010, 22:42
Код

  struct info
   {
    byte players;
    byte maxplayers;
    byte pversion;
    byte type;
    UnicodeString name;
    UnicodeString map;
    UnicodeString game;
    UnicodeString dir;
    short int appid;
    byte bots;
    byte dedi;
    byte os;
    byte pw;
    byte sec;
    UnicodeString gversion;
   };

   info server;

   Memo1->Clear();
   int i,i2;
   server.type = ReceiveBuff[4];
   server.pversion = ReceiveBuff[5];
   for(i=6;ReceiveBuff[i]!=0;i++)
    server.name = server.name + (char)ReceiveBuff[i];
   for(i2=i+1;ReceiveBuff[i2]!=0;i2++)
    server.map = server.map + (char)ReceiveBuff[i2];
   for(i=i2+1;ReceiveBuff[i]!=0;i++)
    server.dir = server.dir + (char)ReceiveBuff[i];
   for(i2=i+1;ReceiveBuff[i2]!=0;i2++)
    server.game = server.game + (char)ReceiveBuff[i2];
   server.appid = ReceiveBuff[i2+1];
   server.players = ReceiveBuff[i2+3];
   server.maxplayers = ReceiveBuff[i2+4];
   server.bots = ReceiveBuff[i2+5];
   server.dedi = ReceiveBuff[i2+6];
   server.os = ReceiveBuff[i2+7];
   server.pw = ReceiveBuff[i2+8];
   server.sec = ReceiveBuff[i2+9];
   for(i=i2+10;ReceiveBuff[i]!=0;i++)
    server.gversion = server.gversion + (char)ReceiveBuff[i];

   if(server.type=='I')
   {
   Memo1->Lines->Add("Source server");
   Memo1->Lines->Add("Версия протокола: "+IntToStr(server.pversion));
   Memo1->Lines->Add("Название: " + server.name);
   Memo1->Lines->Add("Карта: "+server.map);
   Memo1->Lines->Add("Директория сервера: "+server.dir);
   Memo1->Lines->Add("Игра: "+server.game);
   Memo1->Lines->Add("AppID: "+IntToStr(server.appid));
   Memo1->Lines->Add("Players: "+IntToStr(server.players)
   +"/"+IntToStr(server.maxplayers)+" ("+IntToStr(server.bots)+"-bots)");
   if(server.dedi=='l')
     Memo1->Lines->Add("Listen server");
   if(server.dedi=='d')
     Memo1->Lines->Add("Dedicated server");
   if(server.dedi=='p')
     Memo1->Lines->Add("SourceTV server");

   if(server.os=='l')
     Memo1->Lines->Add("OS: Linux");
   if(server.os=='w')
     Memo1->Lines->Add("OS: Windows");

   if(server.pw==0)
     Memo1->Lines->Add("No password");
   else
     Memo1->Lines->Add("Password");
   if(server.sec==0)
     Memo1->Lines->Add("This server is no VAC secured");
   else
     Memo1->Lines->Add("This server is VAC secured");
   Memo1->Lines->Add("Version: "+server.gversion);
   }


Делаю вот так.
Проблема с отображением русских символов в названии и например вместо ★ получается â 
Как исправить?

И ещё, вот например у этих http://www.gametracker.com/search/hl2zp/ серверов AppID должен быть 17505 или 17500, а показывает 92 нужном элементе массива, а в следующем элементе массива вместо 0 становиться 68

Автор: mrbrooks 3.3.2010, 08:45
leporel, UnicodeString использовать вместо массива символов не кошерно. Можно конечно задать строго размер строки, но лучше всеже классический массив символов.

Цитата(leporel @  2.3.2010,  22:42 Найти цитируемый пост)
И ещё, вот например у этих http://www.gametracker.com/search/hl2zp/ серверов AppID должен быть 17505 или 17500, а показывает 92 нужном элементе массива, а в следующем элементе массива вместо 0 становиться 68

17500 == x445C
92 ==  5C
Режется старший байт.

Цитата(leporel @  2.3.2010,  22:42 Найти цитируемый пост)
Проблема с отображением русских символов в названии и например вместо ★ получается â 

откуда там кириллица?

Автор: leporel 3.3.2010, 20:31
Цитата

17500 == x445C
92 ==  5C
Режется старший байт.


как исправить?

Автор: leporel 8.5.2011, 00:44
Может кто объяснить что происходит при
Код

server.appid = *(short*)&ReceiveBuff[i2+1];

Автор: borisbn 8.5.2011, 01:53
не знаю как описан ReceiveBuff, но предположим так
Код

char ReceiveBuff[ 1024 ];

тогда в этом коде
Код

server.appid = *(short*)&ReceiveBuff[i2+1];

делается следующее:
ReceiveBuff[ i2+1 ] // от начала массива ReceiveBuff отступается i2+1 char'ов
&ReceiveBuff[ i2+1 ] // берётся адрес этого (i2+1)-го элемента
(short*)&ReceiveBuff[i2+1] // этот адрес теперь считается не указателем на char, а указателем на short
*(short*)&ReceiveBuff[i2+1] // по этому, вновь созданному указателю, берётся один short (2 байта)
server.appid = *(short*)&ReceiveBuff[i2+1] // этот short записывается в переменную server.appid

Код

ReceiveBuff
|
v
----------------------------------
| 0 |  1 | ... | i2+1 | i2+1 + 2 |
----------------------------------
               ^
               |
               ReceiveBuff[i2+1]
-------------------
| i2+1 | i2+1 + 2 |   <--- вот эти два байта записываются в server.appid
-------------------



 smile 

leporel, а вообще-то прикольно задавать вопрос через год после того, как обсуждение закончилось  smile 

Автор: leporel 8.5.2011, 02:03
borisbn, Спасибо, я просто нашел это в чужой dll, стало интересно, а своих знаний не достаточно.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)