C# Objekt über Socket versenden und empfangen (als Stream)?

3 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Nutzt Du Sockets, weil Du die Herausforderung magst und ganz genau weißt, dass das für 99% der Projekte eine bescheuerte Idee ist?

In dem Fall kannst Du meine Antwort ignorieren.

=====================

Nutze keine Sockets!

Es gibt andere Technologien, die dir das alles abnehmen. Die aktuell vermutlich beste ist ASP.NET, damit kannst Du in wenigen Minuten einen REST- oder gRPC-Services aufbauen, der das alles, worüber Du dir gerade den Kopf zerbrichst, automatisch und vor allem deutlich besser löst, als Du es in den nächsten 10 Jahren könntest.

Mit den Sockets musst Du jeden Kleinkram selber basteln und jedes Detail selber behandeln, das ist ein riesiger Haufen Arbeit und sehr fehleranfällig, das willst Du nur haben, wenn es wirklich nicht anders möglich ist.
Klar, Du kannst dir ein Protokoll ausdenken oder ein Vorhandenes nehmen, aber auch dann musst Du immer noch sehr viel selber machen.

Woher ich das weiß:Berufserfahrung – C#.NET Senior Softwareentwickler

Dultus, UserMod Light  
Fragesteller
 25.04.2022, 17:22

Hm. Okay. REST habe ich auch schon überlegt aber im Gegensatz zu Sockets muss ich dort eben ein ganzes Framework erlernen. Aber mir bleibt wohl nichts übrig. :-)

Danke und LG

0
Palladin007  25.04.2022, 17:39
@Dultus, UserMod Light

REST ist kein Framework, sondern ein Paradigma.
Und kompliziert ist es nicht, im Gegenteil, manche sagen sogar, es ist zu einfach formuliert.

Aber ja, ASP.NET solltest Du lernen, allerdings finde ich das nicht sehr schwierig, im Gegenteil, ich finde es an vielen Stellen sehr genial gelöst. Und einmal verstanden kann es dir auch an vielen anderen Stellen viel Arbeit abnehmen.

Was Du allerdings definitiv lernen solltest, sind die Prinzipien und Patterns hinter ASP.NET, aber die zu lernen würde ich dir sowieso empfehlen, denn davon profitierst Du nicht nur mit ASP.NET.
Und wenn Du dich - wie ich - an diese Prinzipien gewöhnt hast, lernst Du ASP.NET lieben ;) Mein aktuelles Projekt ist z.B. WPF und ich hab erst einmal versucht, ein paar der Prinzipien dafür zu implementieren und das ist nicht gerade einfach, aber es lohnt sich.

2
Dultus, UserMod Light  
Fragesteller
 25.04.2022, 17:42
@Palladin007

Ich bin momentan bei MAUI beim RC1, ich wollte schauen, dass ich von einer App Daten an einen Server senden kann, auf welchem eine weitere Anwendung läuft.

0
Palladin007  25.04.2022, 17:51
@Dultus, UserMod Light

Klassisches Client-Server-System, wie jede Wald-und-Wiesen-App :P

Server: ASP.NET und REST
Client: Refit

Wobei REST nicht irgendwie mehr bedeutet, es heißt nur, dass Du bei den Endpunkten ein bestimmtes Schema einhältst.
Oder Du probierst dich an gRPC, das soll für komplexere Anforderungen besser geeignet sein, eigene Erfahrungen habe ich aber keine.

Aber mit MAUI sollten dir ein paar Dinge bei ASP.NET bekannt vorkommen, da MAUI teilweise die gleichen Frameworks nutzt, die ursprünglich "in" ASP.NET entstanden sind. Ich meine die "Microsoft.Extensions.*"-Frameworks.

1
Dultus, UserMod Light  
Fragesteller
 25.04.2022, 22:39
@Palladin007

Habs darüber wunderbar zum laufen bekommen. Ist wirklich überhaupt nicht schwer. Bereits die Vorlage ist schon fast selbsterklärend.

Super Hinweis gewesen. :D

0
Palladin007  25.04.2022, 22:55
@Dultus, UserMod Light

Lies dir trotzdem die Doku von Microsoft durch, es gibt vieles, was eben nicht so offensichtlich ist, wenn man die Prinzipien nicht kennt.

0
Dultus, UserMod Light  
Fragesteller
 25.04.2022, 23:09
@Palladin007

Das mache ich auf jeden Fall.

Eine Frage, was du zu meinem Vorhaben denkst;

Problem mit API Calls ist ja, dass das ne Momentaufnahme ist. Ich kann zum Beispiel dem Client keinen Fehler zusenden, sondern dieser sich nur einen über die API holen.

Wie wäre es, wenn ich über einen TCP Client eine Verbindung aufbaue, einen Request sende, der Server einen Acknowledge zurückschickt in Form eines Token. Die Verbindung wird aufrecht erhalten.

Der Client schickt einen API Call mit Daten wie Betriebssystem (falls ich z.B. mein Handy anders als meinen Rechner behandeln möchte) zurück und wartet asynchron auf einen Response vom Server.

Dieser würde im Falle eines Problems, zum Beispiel Ausfall eines Programms einen Enum über die Verbindung zurücksenden, welcher für einen Fall steht, dieser wird auf dem Client ausgewertet, ein API Call auf den jeweiligen Fall durchgeführt und eine entsprechende Meldung ausgegeben.

Sinnig?

0
Palladin007  25.04.2022, 23:21
@Dultus, UserMod Light

Versuchst Du auf der App z.B. Status-Informationen live vom Server anzuzeigen?

Muss das wirklich live sein, oder reicht es, wenn das eine kurze Verspätung hat?
Warum fragt die App nicht einfach jede Sekunde nach und bekommt dann entweder nichts oder ein Haufen Daten zurück?

Es gibt sicher noch andere Wege, z.B. könnte der Server einfach so lange (bzw. bis zum Timeout) warten, bis Benachrichtigungen da sind und dann auf den seit Zeit X offenen Request antworten. Wie klug das ist, weiß ich aber nicht, dazu bin ich nicht tief genug im Thema.

Oder Du lässt auf dem Handy einen eigenen kleinen Web-Server laufen, da wäre nur spannend, wie das mit den Ports läuft, die das Betriebssystem ja freigeben muss und ob ASP.NET in MAUI läuft, oder einen eigenen Dienst braucht, ich rate einfach Mal: Es funktioniert in einem eigenen Thread, aber ein paar Hürden wirst Du nehmen müssen.
Das Thema gab's außerdem hier vor ein paar Tagen, ich hab's nur nicht aktiv verfolgt.

0
Dultus, UserMod Light  
Fragesteller
 25.04.2022, 23:26
@Palladin007
Warum fragt die App nicht einfach jede Sekunde nach und bekommt dann entweder nichts oder ein Haufen Daten zurück?

Die Daten werden ja leider jedes Mal wieder neu angefordert. Und wenn das zu häufig stattfindet habe ich Sorge, dass das den Server Performanceweise negativ beeinflusst.

Deshalb der Gedanke mit dem TCPClient, der einfach nebenbei geöffnet bleibt.

Der Server selbst ist ein Linuxserver auf Netcup. Daten umhersenden mit dem TCPClient lief immerhin schon mal. :D

0
Palladin007  25.04.2022, 23:38
@Dultus, UserMod Light
Die Daten werden ja leider jedes Mal wieder neu angefordert. Und wenn das zu häufig stattfindet habe ich Sorge, dass das den Server Performanceweise negativ beeinflusst.

Dann speichere dir den Zeitpunkt, von wann jedes Datum ist und wann jeder Client zuletzt gefragt hat. Jeder Request bekommt dann nur den neuen Kram und unnötiger Overhead ist nur das, was das Protokoll benötigt.

Deshalb der Gedanke mit dem TCPClient, der einfach nebenbei geöffnet bleibt.

Mit selber entwickeln wäre ich bei komplexen Themen vorsichtig, das wird meiner Erfahrung nach früher oder später zum Problem.

Ich hab irgendwie SignalR im Kopf, ich meine, das ist für sowas da.
Ich habe es aber bisher nie genutzt und auch noch nie sowas in diese Richtung gebraucht, daher bin ich da auch nie weiter eingestiegen.

Möglich ist es aber sicher und prinzipiell könnte der Client auch einen komplett eigenen Web-Server aufmachen, das geht alles. Die Frage ist nur, wie kompliziert Du es haben möchtest und die einfachste Lösung wäre, dass z.B. jede Sekunde nach Updates gefragt wird. Das ist sogar so einfach, dass ich es an deiner Stelle einfach mal ausprobieren und testen würde, ob die Performance wirklich zu einem Problem werden könnte.

0
Dultus, UserMod Light  
Fragesteller
 25.04.2022, 23:45
@Palladin007
Dann speichere dir den Zeitpunkt, von wann jedes Datum ist und wann jeder Client zuletzt gefragt hat. Jeder Request bekommt dann nur den neuen Kram und unnötiger Overhead ist nur das, was das Protokoll benötigt.

Was returne ich denn auf dem Server? Hast du ein Codebeispiel?

0
Palladin007  25.04.2022, 23:48
@Dultus, UserMod Light

Ich habe keine Ahnung, was Du vor hast :D

Für mich klingt das so, dass der Server Daten sammelt, also haben die auch ein Datum, von wann sie sind.
Und der Client will immer die neusten Daten haben, also fragt er nach, der Server guckt bei sich dann, wann dieser Client zuletzt gefragt hat und antwortet alles, was seit dem dazu kam. Und wenn es nichts neues gibt, antwortet er halt eine leere Liste.

0

Das Problem dürfte vermutlich sein, dass die Daten in Pakete aufgetrennt werden und somit nicht alle in einem Receive abgefangen wurden. Das ist eine Eigenschaft der IP-Kommunikation.

Somit sollte irgendeine Form von Protokoll drübergestülpt werden. Beispielsweise 4 Byte für die Länge der zu erwartenden Daten + Daten. Somit kann man im ersten Schritt warten, bis man minimum 4 Byte hat (die müssen auf jeden Fall kommen) und dann solange empfangen, bis man die benötigte Anzahl Bytes beisammen hat.

Zudem würde ich zur Sicherheit die Daten vor dem Senden Base64-codieren. So kannst Du sicher sein, dass keine Sonderzeichen Probleme schaffen. In diesem Fall könntest Du Dir dann die Längenbytes sparen und einfach ein \0 hinten anhängen. Dann empfängst Du einfach solange, bis das \0 kommt.

Weiterhin würde ich asynchrone Kommunikation empfehlen. Dann bekommst Du immer dann einen Event, wenn Daten empfangen werden können - Du musst halt in einer geeigneten Variablen die vorher empfangenen Daten speichern.

Ich würde mit dem komfortableren TcpClient arbeiten. Aber gundsätzlich, denke ich, dass da noch Daten im Äther hängen.

Versuch mal folgendes:
Miss die Länge der zu Sendenden Daten und schicke diese Vorab als long Wert rüber.
Denke daran, den Buffer zu Flush(en), denn sonst sind nicht wirklich alle Daten übertragen sondern hängen noch im Client fest.

Lies im Server die ersten 4 Bytes und kenne somit die Länge der zu lesenden Daten, lies so lange, bis diese Größe erreicht ist bevor du deserialisiert.

Woher ich das weiß:Berufserfahrung – Senior-Softwaredeveloper mit 20 Jahren Berufserfahrung.