Wysyłanie dynamicznej tablicy (dynamicznego pakietu) przez sieć

0

Witam,
Mam takie struktury:

type
  TIPv4_Address = Array [0..14] of AnsiChar;
  TMAC_Address = Array [0..16] of AnsiChar;

  TNetworkInterface = packed record
    aIP_Address: TIPv4_Address;
    aMAC_Address: TMAC_Address;
  end;

  PNP_NetworkInterfaceList = ^TNP_NetworkInterfaceList;
  TNP_NetworkInterfaceList = packed record
    dwInterfaceCount: DWORD;
    aInterfaceList: Array of TNetworkInterface;
  end;

Chodzi o to, że chciałbym wysłać strukturę TNP_NetworkInterfaceList poprzez sieć, ale jak widać jest to dynamiczna tablica. Rozszerzam ją sobie za pomocą SetLength, ale za cholerę nie mogę potem wyzerować jej pamięci (ZeroMemory) ani jej wysłać, bo ciągle albo dostaję "Runtime error" albo "Access violation".

Jak poprawnie wysłać taką strukturę? Uzywam standardowych funkcji WinAPI, czyli m.in funkcji send() i recv().

Oczywiście przed wysłaniem właściwego pakietu wysyłam wcześniej mały pakiet informujący o wielkości nadchodzącego pakietu.

0

Kasuje się to też za pomocą SetLength();
Zerowanie również z tym że najpierw ustaw rozmiar na 0 a potem na ten który potrzebujesz - całość będzie wyzerowana.
Ta struktura nie znajduje się w ciągłym obszarze pamięci dla tego nie możesz jej wysłać jednym poleceniem.
Użyj TStringStream wpisz do niego pierwszą składową a potem tablicę.
Pobierz String'a (to co zapisano) ze strumienia i wysyłaj sobie jego zawartość.

0

Ta struktura nie znajduje się w ciągłym obszarze pamięci dla tego nie możesz jej wysłać jednym poleceniem.

No też mi się tak zdawało.

Sęk w tym, że ja nie korzystam z takich bajerów jak TStringStream - serwer jest pisany w WinAPI, używam więc tam głównie: Windows, Messages, Winsock itp. Nawet SysUtils mi nie potrzebne :)
Może jakiś inny sposób?

1

Inne rozwiązanie jest niezbyt ładne, bo świadomie wyłazisz poza strukturę:

type
  TIPv4_Address = Array [0..14] of AnsiChar;
  TMAC_Address = Array [0..16] of AnsiChar;
 
  TNetworkInterface = packed record
    aIP_Address: TIPv4_Address;
    aMAC_Address: TMAC_Address;
  end;
 
  PNP_NetworkInterfaceList = ^TNP_NetworkInterfaceList;
  TNP_NetworkInterfaceList = packed record
    dwInterfaceCount: DWORD;
    aInterfaceList: Array[0..0] of TNetworkInterface;
  end;

const Count=100;
var PNP_NetworkInterfaceList List;
GetMem(List,SizeOf(TNP_NetworkInterfaceList+(Count-1)*SizeOf(TNetworkInterface));
//Tu możesz wyzerować
List.dwInterfaceCount:=Count;
//Tu masz wyłączyć sprawdzanie indeksów
for I:=0 to Count-1 do List.aInterfaceList[I].aIP_Address:=...;

FreeMem(List);
0

To jedyny sposób? Nie ma czegoś bardziej eleganckiego?

1

Właściwie to istnieje tylko dwa sposoby:

  1. Trzymasz to nie w jednym obszarze pamięci, wtedy bez StringStream lub czegoś podobnego własnej roboty nie da rady. Nawet taki głupi pomysł jak zapisanie tego do pliku potem odczytanie tego pliku do tablicy bajtów i jego wysłanie to i tak jest modyfikacja tej metody.
  2. Trzymasz to w jednym fragmencie pamięci, wtedy z wysyłaniem NIE MA problemu, zaś jest problem z przydzieleniem pamięci. To co zaproponowałem też może mieć rózne odmiany np:
  TNP_NetworkInterfaceList = packed record
    dwInterfaceCount: DWORD;
    aInterfaceList: Array[0..(MaxInt-SizeOf(DWORD)-1)div(SizeOf(TNetworkInterface))] of TNetworkInterface;
  end;
const Count=100;
var PNP_NetworkInterfaceList List;
GetMem(List,SizeOf(DWORD)+Count*SizeOf(TNetworkInterface));

Z tym że musisz pamiętać że nie możesz nigdy mieć całego takiego rekordu i będziesz skazany na używanie go przez wskaźnik.
Ale zawsze możesz opakować jeden z takich wariantów w klasę.

0

Dzięki za odpowiedzi.

Szczerze - chciałem wysyłać całą listę jako jeden pakiet żeby było optymalnie. Myślałem, że może ja po prostu sporo pozapominałem (miałem przerwę od Delphi) i zaraz mi tu ktoś poda tak banalne rozwiązanie, że aż wstyd, ale widzę, że jednak tak łatwo nie jest. Może nie będę aż tak kombinował i po prostu dla przykładu zamiast wysłać pakiet z listą 10-ciu interfejsów - wyślę 10 pakietów, a w każdym informacje o danym interfejsie.

Tylko tak się zastanawiam, czy taki sposób nie okaże się problematyczny przy wysyłaniu np. listy plików z danego folderu od "serwera" do "klienta" (GUI). Pewnie będę musiał tu zastosować pół-środek - wysyłać to w paczkach, ale stałych rozmiarów, aby tak nie kombinować.

0

Zawsze możesz zrobić:
aInterfaceList: Array[0..127] of TNetworkInterface;
I wysyłać paczkami po max 128;
Ale i tak będziesz musiał "ręcznie" obliczyć wysyłany rozmiar no i pilnować aby nie wyszło poza 128 szt.

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