Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 20.06.2015, 22:29   #1
NEoMASTERR
Форумчанин
 
Аватар для NEoMASTERR
 
Регистрация: 22.12.2010
Сообщений: 175
Печаль Указатели

Здравствуйте, когда то поработал с указателями и всё было хорошо, потом забил на делфи на пару месяцев, вернулся и я в ступоре, кажется код верный но возникают ошибки доступа Помогите пожалуйста. Делаю класс для мониторинга игровых серверов

Код:
TCsServerListener = class
    udp:TIdUDPClient;
    server:TList;
    timer:TMMTimer;
  private
    constructor Create;
    procedure AddServer(pcs:pCsServer);
    procedure Listen(Sender: TObject);
    procedure GetChallenge(pcs:PCsServer);
    function Send(pcs:PCsServer; var buf; buflen:Word):string;

////

procedure TCsServerListener.AddServer(pcs: pCsServer);
begin
  if server.IndexOf(pcs)=-1
  then server.Add(pcs);
end;
Собственно класс модуля мониторинга, он один по таймеру бегает по server:TList и "пингует" их по очереди
Но почему то в TList этом что то непонятное происходит, либо я накасячил.

Код:
constructor TCsServer.Create(ip: string; port: Word; rcon: string);
begin
  inherited Create;
  FIp:= ip;
  FPort:=port;
  FRcon:=rcon;
  FListener:=@Listener;                     // Заполняем поле
  FListener^.AddServer(@self);           // Добавляем себя в Listener 
  FCounter := 0;
end;
А вот тут то и начинается веселье

Код:
procedure TCsServerListener.Listen(Sender: TObject);
var
  i,j:integer;
  pcs:PCsServer;
  s:string;
  ts:TStringList;
begin
  if server.Count > 0 then
  begin
    ts:=TStringList.Create;

    for i:=0 to server.count -1 do
    begin
      pcs:=PCsServer(server[i]);                           // - в pcs^ будет inacessible value, хотя в pcs вроде верный адрес

      if (Assigned(pcs)) and (pcs <> nil) then
      begin
        if pcs^.FRconChallenge = '' then
        begin
          GetChallenge(pcs);
Здравствуйте

Последний раз редактировалось NEoMASTERR; 20.06.2015 в 22:43.
NEoMASTERR вне форума Ответить с цитированием
Старый 21.06.2015, 07:21   #2
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
FListener:=@Listener;
Это указатель на объект?
Цитата:
pcs:PCsServer;
А мона нескромный вопрос?: Зачем ты работаешь с объектами по указателям? Препод "шатаит"?
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 21.06.2015, 09:48   #3
NEoMASTERR
Форумчанин
 
Аватар для NEoMASTERR
 
Регистрация: 22.12.2010
Сообщений: 175
По умолчанию

Цитата:
Сообщение от Stilet Посмотреть сообщение
Это указатель на объект?
Да
Код:
implementation

var
  Listener:TCsServerListener;
Цитата:
Сообщение от Stilet Посмотреть сообщение
А мона нескромный вопрос?: Зачем ты работаешь с объектами по указателям? Препод "шатаит"?
Стесняюсь ответить) Мне нравится с ними работать (нравилось раньше, удобней), сейчас видимо всё позабыл, да и для TList все равно нужен указатель а не сам объект
Здравствуйте
NEoMASTERR вне форума Ответить с цитированием
Старый 21.06.2015, 11:59   #4
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
да и для TList все равно нужен указатель а не сам объект
А ты замени его на TObjectList().
Я чесслово пока что не понял что у тебя происходит по твоим обрывкам. Если хочешь - приложи полный код. Но лучше в ООП с указателями не работать.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 21.06.2015, 12:34   #5
NEoMASTERR
Форумчанин
 
Аватар для NEoMASTERR
 
Регистрация: 22.12.2010
Сообщений: 175
По умолчанию

Цитата:
Сообщение от Stilet Посмотреть сообщение
А ты замени его на TObjectList().
Я чесслово пока что не понял что у тебя происходит по твоим обрывкам. Если хочешь - приложи полный код. Но лучше в ООП с указателями не работать.
Код я немного переделал до рабочего пока не помогут с указателями, но сейчас верну к тому и скину. Просто перед этим я делал мессенджер и там всё норм работало, передавал record указателями

>>>>> Аттач
Здравствуйте

Последний раз редактировалось NEoMASTERR; 21.06.2015 в 12:37.
NEoMASTERR вне форума Ответить с цитированием
Старый 21.06.2015, 13:33   #6
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Мой антивирус нашел в твоем коде (аттаче) ошибку
Мой антивирус тоже против работы с указателями )))
Если код небольшой то прямо сюда его впиши. можно несколькими сообщениями, я потом при необходимости поправлю и окультурю.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 21.06.2015, 15:41   #7
NEoMASTERR
Форумчанин
 
Аватар для NEoMASTERR
 
Регистрация: 22.12.2010
Сообщений: 175
По умолчанию

Код:
unit cs_class;
interface

uses SysUtils, Classes, IdBaseComponent, IdComponent, IdUDPBase, IdUDPClient, IdSocketHandle, mmTimer;

type TStringArray = array of string;

procedure Log(s:string);
procedure explode(s:string; var arr:TStringArray; const delim:Char = ' ');

type
  PCsServerListener = ^TCsServerListener;
  PCsServer = ^TCsServer;

  TCsPlayer = record
    id: Byte;
    name:string;
    userid:Word;
    authid:string;
    frag:Word;
    time:string;
    ping:Word;
    loss:word;
    adr:string;
  end;

  TCsServer = class
    FRcon:string;
    FRconChallenge:string;
    FIp:string;
    FPort:word;
    FListener: PCsServerListener;
    FCounter:word;
    FHostname:string;
    FVer:string;
    FMap:string;
    FPlayers:array [0..31] of TCsPlayer;
    FPlayers_count:byte;
    FPlayers_max:Byte;
    public
      constructor Create(ip:string; port:Word; rcon:string);
      function RconCommand(s:string):string;
  end;

  TCsServerListener = class
    udp:TIdUDPClient;
    server:TList;
    timer:TMMTimer;
  private
    constructor Create;
    procedure AddServer(pcs:pCsServer);
    procedure Listen(Sender: TObject);
    procedure GetChallenge(pcs:PCsServer);
    function Send(pcs:PCsServer; var buf; buflen:Word):string;
  end;

implementation
uses unit1;

var
  Listener:TCsServerListener;

// разбиваем строку на массив
procedure explode(s:string; var arr:TStringArray; const delim:Char = ' ');
var
  ts:TStringList;
  i:integer;
begin
  ts:=TStringList.Create;
  ts.Delimiter:=delim;
  ts.DelimitedText:=s;
  if ts.Count>0 then
  begin
    SetLength(arr,ts.Count);
    for i:=0 to ts.Count-1 do
    begin
      arr[i]:=ts[i];
    end;
  end;
end;

procedure Log(s:string);
begin
  form1.mmo2.lines.add(s);
end;

{ TCsServer }

constructor TCsServer.Create(ip: string; port: Word; rcon: string);
begin
  inherited Create;
  FIp:= ip;
  FPort:=port;
  FRcon:=rcon;
  FListener:=@Listener;         // добавляем адрес класса (в будущем они могут различаться если сделаю полноценный движок для разных игр
  FListener^.AddServer(@self);  // вызываем добавление себя в список (работает вроде)
  FCounter := 0;
end;

function TCsServer.RconCommand(s: string):string;
begin
  s:='яяяяrcon '+FRconChallenge+' "'+FRcon+'" '+s;
  result := FListener^.Send(@Self,s[1],Length(s));       // посылаем на сервер команду
end;

{ -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= TCsServerListener =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- }
constructor TCsServerListener.Create;
begin
  udp:=TIdUDPClient.Create(nil);
  udp.ReceiveTimeout:=1000;
  udp.BufferSize:=1400;
  server:=TList.Create;
  timer:=TMMTimer.Create;
  timer.Interval:=1000;
  timer.OnTimer:=Listen;
  timer.Enabled:=True;                          // тут понятно всё
end;
Здравствуйте
NEoMASTERR вне форума Ответить с цитированием
Старый 21.06.2015, 15:41   #8
NEoMASTERR
Форумчанин
 
Аватар для NEoMASTERR
 
Регистрация: 22.12.2010
Сообщений: 175
По умолчанию

Код:
procedure TCsServerListener.Listen(Sender: TObject);
var
  i,j,x:integer;
  pcs:PCsServer;
  s:string;
  ts:TStringList;
  arr:TStringArray;
begin
  if server.Count > 0 then
  begin
    ts:=TStringList.Create;

    for i:=0 to server.count -1 do
    begin
      pcs:=PCsServer(server[i]);                          //////// ПРОБЛЕМА НАЧИНАЕТСЯ ТУТ
                                                          // всё переделывать не стал, так что где pcs без ^ это норм,
                                                          // заменю pcs:PcsServer на TCsServer и работает
                                                          // но интересно сделать указателями =)

      if (Assigned(pcs)) and (pcs <> nil) then
      begin
        if pcs^.FRconChallenge = '' then                  // нет ключа, получим, но тут уже error т.к. pcs^ видимо равен 0
        begin
          GetChallenge(pcs);
        end
        else
        begin
          if pcs.FCounter mod 3 = 0 then                  // получаем игроков раз в 3 сек
          begin                                           // дальше парсинг
            Form1.mmo2.Lines.Clear;
            s:=Trim(pcs.RconCommand('status'));
            if s='' then Break;
            log('Received:'+s);
            ts.Text:=s;

            pcs.FHostname:=trim(copy(ts[0],pos(':', ts[0])+1, Length(ts[0])));
            pcs.FVer :=trim(copy(ts[1],pos(':', ts[1])+1, Length(ts[1])));
            pcs.FMap:=trim(copy(ts[3],pos(':', ts[3])+1, Length(ts[3])));

            s:=copy(ts[4],11,length(ts[4]));
            s:=StringReplace(s,'(',' ',[rfReplaceAll]);
            s:=StringReplace(s,')',' ',[rfReplaceAll]);

            explode(s,arr);

            pcs.FPlayers_count := strtoint(arr[0]);
            pcs.FPlayers_max := strtoint(arr[2]);

            for j:=0 to 6 do ts.delete(0);

            log('LastLine = '+ts[ts.count-1]);
            if ts.Count>0 then ts.delete(ts.count-1);

            if ts.count>0 then
            begin
              x:=0;
              for j:=0 to ts.Count-1 do
              begin
                if x>High(pcs.FPlayers) then break;
                s:=copy(ts[j],2,length(ts[j]));
                if copy(s,2,length(s)) = 'users' then Break;
                if Trim(s) = '' then break;

                explode(s,arr);
                
                if Length(arr)<9 then
                begin
                  SetLength(arr,9);
                  arr[8]:='0';
                end;

                pcs.FPlayers[x].id:=StrToInt(arr[0]);
                pcs.FPlayers[x].name:=Utf8ToAnsi(arr[1]);
                pcs.FPlayers[x].userid:=strtoint(arr[2]);
                pcs.FPlayers[x].authid:=arr[3];
                pcs.FPlayers[x].frag:=strtoint(arr[4]);
                pcs.FPlayers[x].time:=arr[5];
                pcs.FPlayers[x].ping:=strtoint(arr[6]);
                pcs.FPlayers[x].loss:=strtoint(arr[7]);
                pcs.FPlayers[x].adr:=arr[8];

                log(pcs.FPlayers[x].name+'['+inttostr(pcs.FPlayers[x].id)+']');
                inc(x);
              end;
              Log(inttostr(x)+' players parsed');
            end;
          end;
        end;
        inc(pcs.FCounter);
      end;
    end;

    ts.free;
  end;
end;

function TCsServerListener.Send(pcs:PCsServer; var buf; buflen:Word):string;
var
  s:PChar;
  b:array [0..1400] of char;
  l:array [0..1400] of char;
  i:Integer;
begin
  Result:='';                                               // чистим старый результат
  FillChar(b[0],length(b),#0);                              // это понятно
  udp.SendBuffer(pcs^.FIp, pcs^.FPort, buf, buflen);        // отсылаем
  i:=1;
  while i<>0 do
  begin                                                     // пока не 0 получаем
    i:=udp.ReceiveBuffer(b[0],length(b));
    log('Received size: '+inttostr(i)+' bytes');
    if i = 0 then break;
    if copy(string(b),1,4) = 'юяяя' then move(b[9],b[0],length(b));    // вырезаем особенности пакетов движка
    if copy(string(b),1,5) = 'яяяяl' then move(b[5],b[0],length(b));
    log('Received text: ###'+copy(string(b),1,i)+'###');
    Result := Result + copy(string(b),1,i);
  end;
end;

procedure TCsServerListener.GetChallenge(pcs: pCsServer);
var
  s:string;
begin
  s:='яяяяchallenge rcon';

    udp.SendBuffer(pcs^.FIp, pcs^.FPort, s[1], 18);

  try
    s:=udp.ReceiveString;
  except
  end;
  if Pos('No challenge',s) = 0 then pcs^.FRconChallenge := trim(copy(s, 19,Length(s)));
end;


procedure TCsServerListener.AddServer(pcs: pCsServer);
begin
  if server.IndexOf(pcs)=-1                                  // возможно добавляет что то не то -_-
  then server.Add(pcs);
end;

begin
  Listener:= TCsServerListener.Create;
end.
Здравствуйте
NEoMASTERR вне форума Ответить с цитированием
Старый 21.06.2015, 15:42   #9
NEoMASTERR
Форумчанин
 
Аватар для NEoMASTERR
 
Регистрация: 22.12.2010
Сообщений: 175
По умолчанию

Использование
Код:
var  cs: array of TCsServer;

implementation

{$R *.dfm}

procedure TForm1.btn3Click(Sender: TObject);
begin
  SetLength(cs, 1);
  cs[0]:=TCsServer.Create('127.0.0.1', 27020, 'tratata');
end;
Спасибо за уделенное время
Здравствуйте
NEoMASTERR вне форума Ответить с цитированием
Старый 21.06.2015, 16:12   #10
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Хм...
Для начала предположу что @self - кавайные грабли. Self это и так указатель так что может быть стоит писать как Pointer(Self) вместо передачи указателя на указатель.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Указатели СИ. Morowind Помощь студентам 1 12.09.2012 19:20
Указатели человек&кошка Помощь студентам 2 15.02.2012 07:26
указатели Артэс Общие вопросы C/C++ 11 07.02.2010 16:47
Указатели IceBreaker Общие вопросы C/C++ 9 05.02.2010 09:11
[C] массивы, указатели, двойные указатели. Iggel Общие вопросы C/C++ 5 05.05.2009 12:39