2009-10-24 3 views
5

Muszę przesłać strukturę C przez przewód (przy użyciu gniazd UDP i ewentualnie XDR w pewnym momencie) przy dość wysokiej częstotliwości aktualizacji, która potencjalnie powoduje wiele zbędny i niepotrzebny ruch w kilku khz.Jak kodować strukturę C/C++ delta do transmisji za pośrednictwem gniazd

To dlatego, że niektóre dane w strukturze mogły się nie zmieniać czasami, więc pomyślałem, że delta-kodowanie bieżącej struktury C przeciwko poprzedniej strukturze C wydaje się dobrym pomysłem, prawie jak " diff ".

Ale zastanawiam się, jakie jest najlepsze podejście do robienia czegoś takiego, najlepiej w przenośny sposób, który zapewnia również integralność danych? Czy byłoby możliwe proste przetwarzanie danych i postępowanie w ten sposób?

Podobnie, ważne jest, aby podejście było wystarczająco rozszerzalne, aby nowe pola mogły zostać dodane do struktury lub uporządkowane, jeśli to konieczne (dopełnienie), co również brzmi tak, jakby wymagało informacji o wersjach.

Wszelkie pomysły i wskazówki (czy istnieją biblioteki?) Byłyby wysoko cenione!

Dzięki

EDIT: Dzięki wszystkim jednego, który dostarczył odpowiedzi, poziom szczegółowości jest bardzo ceniona, zdaję sobie sprawę, że prawdopodobnie nie powinien wymienić choć UDP, ponieważ w rzeczywistości nie jest głównym problemem, ponieważ istnieje już odpowiedni protokół zaimplementowany na UDP, który uwzględnia wspomniane trudności, więc pytanie miało w rzeczywistości być specyficzne dla możliwych środków delta kodujących strukturę, a nie tyle o użyciu UDP w szczególności jako mechanizmu transportowego .

+0

Myślę, że to zależy od tego jak dużo dane będą się zmieniać (1%? 10%? 50%?) i jak regularne są zmiany (czy są w tych samych miejscach czy wszędzie?) –

+0

Po prostu ciekawy: dlaczego struktura C w przeciwieństwie do używania czegoś takiego jak XMLRPC, SOAP lub inny komunikator mechanizmy unication takie jak DBUS? Co się stanie ze strukturą, kiedy pojawi się po drugiej stronie? – aneccodeal

Odpowiedz

4

UDP nie gwarantuje, że dany pakiet został faktycznie otrzymane, więc kodowanie cokolwiek przekazać jako „różnica w ostatniej chwili” jest problematyczne - nie można wiedzieć że odpowiednik ma ten sam pomysł co ty o co "ostatnim razem" był. Zasadniczo będziesz musiał skomponować pewien nadmiar na UDP, aby sprawdzić, jakie pakiety zostały odebrane (oznaczając każdy pakiet unikalnym identyfikatorem) - każdy, kto próbował iść tą trasą, zgodzi się, że częściej niż ty znajdziesz się więcej lub mniej powielania infrastruktury przesyłania strumieniowego TCP na górze UDP ... tylko najprawdopodobniej nie jest tak solidna i dobrze rozwinięta (choć czasami czasami można skorzystać z bardzo szczególnych cech swoich ładunków, aby uzyskać skromną przewagę nad dobrym stary TCP).

Czy transmisja musi być jednokierunkowa, z nadajnika do odbiornika? Jeśli tak jest (tzn. Odbiorca nie może wysyłać potwierdzeń lub retransmisji), to naprawdę niewiele można zdziałać w tym kierunku. Jedna rzecz, która przychodzi na myśl: jeśli odbiornik nie jest zsynchronizowany przez jakiś czas, może wysłać dwa rodzaje pakietów - jeden z pełnym obrazem aktualnej wartości struktury i identyfikacją unikalny znacznik, który ma być wysłany co najmniej na każde (powiedzmy) 5 minut (tak realistycznie odbiornik może być zsynchronizowany przez maksymalnie 15 minut, jeśli pominie dwa z tych "dużych pakietów"); jeden z aktualizacją (różnicą) z ostatniego "dużego pakietu", w tym znaczący unikalny znacznik dużego pakietu i (np.) zakodowana w czasie wersja XOR, o której wspomniałeś.

Oczywiście po przygotowaniu wersji z zakodowaną długością, serwer porówna jego rozmiar z rozmiarem całej struktury, a jedynie przesłać pakiet typu delta, jeśli oszczędności są znaczne, w przeciwnym razie może dobrze wysłać duży pakiet nieco wcześniej niż potrzeba (zyskuje na niezawodności). Otrzymany będzie śledzić ostatni otrzymany unikalny znacznik dużego pakietu i stosować tylko delty, które go dotyczą (pomaga uniknąć brakujących pakietów i pakietów dostarczonych poza kolejnością, w zależności od tego, jak wyrafinowane chcesz zrobić klienta).

Konieczność zmiany wersji & c, w zależności od tego, co dokładnie masz na myśli (czy nadawcy i odbiorcy z różnymi pomysłami na temat wyglądu układu w układzie C będą musieli regularnie komunikować się, w jaki sposób uzgadniają, jakie wersje są znane obu? itd.), doda jeszcze całego wszechświata komplikacji, ale to jest naprawdę inne pytanie, a twoje podstawowe pytanie, które zostało streszczone w tytule, jest już wystarczająco duże ;-).

Jeśli możesz pozwolić sobie na sporadyczne meta-wiadomości od odbiornika z powrotem do nadawcy (pakiety lub prośby o ponowne wysłanie), to w zależności od różnych parametrów liczbowych w grze możesz zaprojektować różne strategie. Podejrzewam, że gacki musiałyby być dość częste, by zrobić dużo dobrego, więc prośba o ponowne wysłanie dużego pakietu (albo konkretnie zidentyfikowanego, albo "cokolwiek masz, co jest najświeższe") może być najlepszą meta-strategią do wybrania przestrzeni opcji (które w przeciwnym razie grozi wybuchem ;-). Jeśli tak, to nadawca może być błogo nieświadomy jakiejkolwiek strategii, której używa odbiorca, aby zażądać ponownej wysyłki dużych pakietów, i możesz eksperymentować po stronie odbiorcy z różnymi strategiami bez konieczności ponownego wdrażania nadawcy.

Trudno zaoferować o wiele więcej pomocy bez pewnych szczegółów, tj. Przynajmniej numery stanowisk dla wszystkich parametrów liczbowych - wielkości pakietów, częstotliwości wysyłania, jak długo jest tolerowany, aby nadawca nie był zsynchronizowany z odbiornik, pakiet parametrów sieciowych itp. Ale mam nadzieję, że ta nieco ogólna analiza i sugestie nadal będą pomocne.

3

kodowania delta:

1) Wyślij "kluczowe ramki" okresowo (na przykład raz na sekundę). Klatka kluczowa to kompletna kopia (a nie delta), więc jeśli z jakiegoś powodu utracisz komunikatory, utracisz tylko niewielką ilość danych, zanim znowu "zdobędziesz sygnał". Użyj prostego nagłówka pakietu, który pozwala wykryć początek pakietu i wiedzieć, jakie dane zawiera.

2) Oblicz deltę z poprzedniego pakietu i zakoduj ją w zwartej formie. Badając typ wysyłanych danych i sposób ich typowej zmiany, powinieneś być w stanie zaprojektować całkiem zwarty delta. Może jednak zajść potrzeba sprawdzenia rozmiaru delty - w niektórych przypadkach może to nie być wydajne kodowanie - jeśli jest większy niż klatka kluczowa, można zamiast tego wysłać inną klatkę kluczową. W tym momencie możesz także zdecydować, czy twoje delty są stratne czy bezstratne.

3) Dodaj kontrolę CRC do pakietu (wyszukaj CRC32). Umożliwi to odbiorcy sprawdzenie, czy pakiet został odebrany w stanie nienaruszonym, umożliwiając im pominięcie nieprawidłowych pakietów.

UWAGI:

  • być ostrożnym w ten sposób przez UDP - daje żadnej gwarancji, że pakiety będą przybywać w tej samej kolejności, w jakiej je wysłał. Oczywiście delta zadziała tylko wtedy, gdy pakiety są w porządku. W takim przypadku będziesz musiał dodać jakąś formę identyfikatora sekwencji do każdego pakietu (pierwszy pakiet to "1", drugi pakiet to "2" itd.), Aby można było wykryć odbiór poza kolejnością. Możesz nawet zachować bufor pakietów "n" w odbiorniku, aby móc je ponownie złożyć w odpowiedniej kolejności, kiedy będziesz je dekodować (ale oczywiście może to spowodować opóźnienie). Prawdopodobnie przegapisz także niektóre pakiety przez UDP, w takim przypadku musisz poczekać do następnej klatki kluczowej, zanim będziesz w stanie "ponownie odebrać sygnał" - aby klatki kluczowe były wystarczająco częste, aby uniknąć katastrofalnych przestojów w twoich commach.

  • Rozważ użycie kompresji (np. Zip itp.). Może się okazać, że pełny pakiet może być zbudowany w przyjazny dla suwaka sposób (np. Dane z zapisu wstecznego na bajty grupowe, które prawdopodobnie mają podobne wartości (szczególnie zera)), a następnie skompresowany tak dobrze, że jest mniejszy niż nieskompresowana delta, i nie będziesz musiał w ogóle angażować się w delta (i nie będziesz musiał się martwić o porządkowanie pakietów itp.).

edit - Zawsze należy używać numeru wersji (lub typ pakietu) w swoich pakietach, dzięki czemu można dodać nowe pola lub zmienić kodowanie delta w przyszłości! Będziesz potrzebował tego do różnicowania ramek klawiszy/trójkątów.

+0

Czy Twoja pierwsza uwaga nie byłaby bardziej zwięźle napisana jako "wymyślanie TCP"? –

+0

Po prostu dodam, dzięki za wejście w ten poziom szczegółowości, to naprawdę doceniane. – guest

+0

@guest - bez obaw. Mam nadzieję, że to było pouczające/interesujące, nawet jeśli nie zapewniało rozwiązania, którego szukałeś. –

1

Nie jestem przekonany, że kodowanie wartości delta na UDP - co jest z natury niewiarygodne i nie w porządku - będzie szczególnie łatwe. Zamiast tego wyślę identyfikator zmienionego pola i jego aktualną wartość. Nie wymaga to również żadnych zmian, jeśli chcesz dodać dodatkowe pola do wysyłanej struktury danych. Jeśli potrzebujesz standardowego sposobu robienia tego, spójrz na SNMP; może to być coś, na co możesz wpaść lub może być trochę luźny (kwalifikuje nazwy pól globalnie i używa ASN.1 - oba dają maksymalną interoperacyjność, ale kosztem niektórych bajtów w pakiecie).

0

Użyj RPC jak CORBA lub protokół buforów

Zastosowanie DTLS z opcją kompresji

Korzystanie spakowanego formatu

Repurposes istniejącą bibliotekę kompresji nagłówka

Powiązane problemy