IdTCPServer i IdTCPClient wiadomości w rekordach

IdTCPServer i IdTCPClient wiadomości w rekordach
chkam
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 4 lata
  • Postów:59
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:

Kopiuj
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:

Kopiuj
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:

Kopiuj
  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?

edytowany 1x, ostatnio: chkam
GS
  • Rejestracja:ponad 14 lat
  • Ostatnio:3 minuty
0

coś masz poplątane z typami zmiennych

Kopiuj
 var
  NewMessage: TMessage;
 

i

Kopiuj
 NewMessage.MsgData := TStringList.Create;

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

chkam
Nawet po zostawieniu sobie jednej zmiennej nic nie działa w dalszym ciągu
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Gorlice
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/.


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
edytowany 1x, ostatnio: kAzek
chkam
Mam najnowsze Delphi XE6 razem z Indy10
abrakadaber
abrakadaber
  • Rejestracja:ponad 12 lat
  • Ostatnio:8 miesięcy
  • Postów:6610
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


Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
chkam
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 4 lata
  • Postów:59
0

Temat do zamknięcia

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

Kopiuj
InMessage.Position := 0;
chkam
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 4 lata
  • Postów:59
0

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

Kopiuj
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:

Kopiuj
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;
edytowany 1x, ostatnio: chkam
abrakadaber
abrakadaber
  • Rejestracja:ponad 12 lat
  • Ostatnio:8 miesięcy
  • Postów:6610
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.


Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
edytowany 1x, ostatnio: abrakadaber
chkam
Tak zamieniłem i działa w jedną stronę, w drugą odczyt zawiesza klienta a serwer nie wiem czy dobrze wysyła. Ogólnie całość chodzi gdy wysyłam jeden string: TIdContext(List.Items[Count]).Connection.IOHandler.WriteLn;
chkam
TStrings wyrzuciłem jak przerzucam z TStringList.Text na String/shortstring a potem zpowrotem na TStringsList to zachowują się przejścia do nowych linijek
chkam
Ogólnie chciałbym ogarnąć odbiór i wysyłanie TStream bo nie ważne co bym przekonwertował na stream on się wiesza
flowCRANE
@chkam - banik, czy dobrowolnie przestaniesz przerzucać dyskusję do komentarzy?
chkam
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 4 lata
  • Postów:59
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.

chkam
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 4 lata
  • Postów:59
0

Dokonałem paru zmian w programie:

Serwer:

Kopiuj
  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:

Kopiuj
    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

Kopiuj
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ąć.

edytowany 7x, ostatnio: chkam
flowCRANE
W pierwszym podanym kodzie, oznaczonym "Serwer" wypadałoby użyć instrukcji wiążącej;

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.