IdTCPServer i IdTCPClient wiadomości w rekordach

0

Witam

Robię do szkoły mały program który będzie pozwalał na komunikację się użytkowników komputerów.
Całość robię na Indy IdTCPServer/Client.
Połączenie i wszystko chodzi całkiem nieźle póki nie zacznę przesyłać danych, błędów nie ma ale problem jest taki że nic nie przychodzi.

Kod Serwera:

procedure TSForm_Server.IdTCPServer1Execute(AContext: TIdContext);
var
  NewMessage: TMessage;
  InMessage: TMemoryStream;
  i : integer;
begin
  InMessage := TMemoryStream.Create;
  NewMessage.MsgData := TStringList.Create;

  AContext.Connection.IOHandler.ReadStream(InMessage, SizeOf(NewMessage));
  InMessage.Read(NewMessage, SizeOf(NewMessage));

  Memo_Display.Lines.Add('> New User');
  Memo_Display.Lines.Add('+------------------------------------------------+');
  Memo_Display.Lines.Add('> Data:   '+NewMessage.MsgDate+' '+NewMessage.MsgTime);
  Memo_Display.Lines.Add('> InIP:   '+NewMessage.MsgInIP);
  Memo_Display.Lines.Add('> OutIP:  '+NewMessage.MsgOutIP);
  Memo_Display.Lines.Add('> From:   '+NewMessage.MsgSender);
  Memo_Display.Lines.Add('> To:     '+NewMessage.MsgReciver);
  Memo_Display.Lines.Add('> Message:');
  for i := 0 to NewMessage.MsgData.Count-1 do begin
    Memo_Display.Lines.Add(NewMessage.MsgData.Strings[i]);
  end;
  Memo_Display.Lines.Add('+------------------------------------------------+');

end;

Kod Klienta:

procedure TSForm_Client.SendMessage(Sender: TObject);
var
  NewMessage : TMessage;
  OutMessage : TMemoryStream;
begin
  NewMessage.MsgInIP := IPIn;
  NewMessage.MsgOutIP := IPOut;
  NewMessage.MsgSender := Edit_Nick.Text;
  NewMessage.MsgReciver := 'Server';
  NewMessage.MsgTime := TimeToStr(Now);
  NewMessage.MsgDate := DateToStr(Now);
  NewMessage.MsgData := TStringList.Create;
  NewMessage.MsgData.Assign( Memo1.Lines );

  OutMessage := TMemoryStream.Create;
  OutMessage.Write(NewMessage, sizeOf(NewMessage));

  OutMessage.Position := 0;
  IdTCPClient1.IOHandler.Write(OutMessage);
end;

Klasa Rekordu, wszędzie ta sama:

  TMessage = record
    MsgInIP: string;
    MsgOutIP: string;
    MsgSender: string;
    MsgReciver: string;
    MsgTime: string;
    MsgDate: string;
    MsgData: TStrings;
  end;

W jakim miejscu popełniłem błąd?

0

coś masz poplątane z typami zmiennych

 var
  NewMessage: TMessage;
 

i

 NewMessage.MsgData := TStringList.Create;

Już w kompilacji wyrzuca błąd :
E2003 Undeclared identifier: 'MsgData'

0

To nie poplątane typy zmiennych a wersje Indy bo niestety 9 nie jest zgodne z 10 są inne właściwości tzn.odpowiadająca za to samo właściwość nazywa się inaczej w 10 a inaczej w 9 dlatego jeżeli chcesz pomocy z indy to przede wszystkim zaktualizuj do najnowszej wersji http://indy.fulgan.com/ZIP/.

0

nie możesz mieć pola typu string i tak go zapisywać bo zapisujesz sam wskaźnik na miejsce w pamięci a nie rzeczywisty napis. Musisz użyć ShortString

0

Temat do zamknięcia

Pod odczytaniu Streamu, program próbował odczytać tylko jego koniec, trzeba było wrócić do jego początku.

InMessage.Position := 0;
0

Znalazłem kolejny problem tym razem przy odczycie wiadomości:

procedure TSForm_Client.Recive_Message;
var
  NewMessage : TMessage;
  InMessage : TMemoryStream;
begin
  if IdTCPClient1.Connected = false then Exit;

  InMessage := TMemoryStream.Create;

  try
    //InMessage := IdTCPClient1.IOHandler.ReadStream();
    IdTCPClient1.IOHandler.ReadStream(InMessage, SizeOf(NewMessage));
  except
    Memo_Display.Lines.Add('client > Recive Error');
    Exit;
  end;
  InMessage.Position := 0;
  InMessage.Read(NewMessage, SizeOf(NewMessage));
  ShowMessage(NewMessage.MsgSender);
end;

Po uruchomieniu tej procedury cały program mi ścina (to jest na razie testowy kod)

Odpowiedź z serwera wygląda tak:

procedure TSForm_Server.IdTCPServer1Recive(AContext: TIdContext);
var
  NewMessage: TMessage;
  OutMessage: TMemoryStream;
  List: TList;
  Count : integer;
begin
  List := IdTCPServer1.Contexts.LockList;
  try
    for Count := 0 to List.Count -1 do
    begin
      NewMessage.MsgSender := 'Test';
      OutMessage := TMemoryStream.Create;
      OutMessage.Write(NewMessage, sizeOf(NewMessage));
      TIdContext(List.Items[Count]).Connection.IOHandler.Write(OutMessage, SizeOf(NewMessage));
    end;
  finally
    IdTCPServer1.Contexts.UnlockList;
  end;
end;
0

zamieniłeś string na shortstring?
To samo z typem TStrings w rekordzie - nie możesz mieć typów złożonych i go tak wysyłać. Jak chcesz mieć zwykłe stringi i klasy to musisz to wysyłać "ręcznie", tzn. to co teraz robisz nie wysyła Ci danych z TStrings tylko sam wskaźnik w pamięci, gdzie się instancja tej klasy znajduje.

0

Ogólnie zamieniłem String na ShortString, a następnie pozbyłem się TStrings.
Chciałbym rozwiązać problem przesyłania streamu bo wysyłanie i odbieranie przy użyciu WriteLn o ReadLn, działają poprawnie.

0

Dokonałem paru zmian w programie:

Serwer:

  List := IdTCPServer1.Contexts.LockList;
  try
    for Count := 0 to List.Count -1 do begin
      with TIdContext(List.Items[Count]).Connection.IOHandler do begin
        Write(LongInt(InMessage.Size));
        WriteBufferOpen;
        Write(InMessage, 0, False);
        WriteBufferFlush;
      end;
  finally
    IdTCPServer1.Contexts.UnlockList;
  end;

Klient:

    LSize := IdTCPClient1.IOHandler.ReadLongInt();
    IdTCPClient1.IOHandler.ReadStream(InMessage, LSize, False);

Klient odbierze TStream od od serwera i go odczyta ale problem pojawia się kiedy tą wiadomość skończy czytać i oczekuje na kolejną której nie ma i prawdopodobnie odczytuje pustkę lub losowy ciąg danych który go po prostu wiesza, a program musi nasłuchiwać/czekać na kolejną wiadomość.

W przypadku

Zmienna := IdTCPClient1.IOHandler.ReadLn('', 5)

nie było problemów ale odczytywana była jedna zmienna.
W przypadku podmiany tego kodu i wysyłania najpierw rozmiaru streamu jako tekst, odczyta on go tylko raz, bo przy kolejnym odczytywaniu w miejsce odczytu stringa wciska się TStream który bierze się tak jakby znikąd bo serwer wysyła tylko jedną wiadomość a potem klient czyta pustkę aż do czasu kolejnego wysyłu pakietu: string, stream z serwera, po czym na sam początek przychodzi coś czego string nie jest w stanie przyjąć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1