Websocket Verbindung zwischen Android Client und Erlang Server?

2 Antworten

Vom Fragesteller als hilfreich ausgezeichnet
Serverseitig würde ich gerne den Websocketserver mit Erlang programmieren, (...)

Ich denke, am einfachsten fährst du da auf Basis von Yaws (ein Webserver mit WebSocket-Support) oder Cowboy (siehe SockJS-erlang oder die Implementation von Marcelo Gornstein).

(...) jedoch finde ich keine ausreichenden Quellen, wie ich den Client in AndroidStudio/Java umsetzen kann, sodass er auch auf Servernachrichten reagiert.

Nimm eine Bibliothek wie Java-WebSocket. Die ExampleClient.java zeigt, wie es funktioniert: Die WebSocketClient-Instanz verfügt über eine send-Methode, um Nachrichten an den Server zu schicken und kann in onMessage wiederum empfangene Nachrichten verarbeiten.

Ebenso könntest du die Implementation von JakartaEE verwenden. Im Oracle Blog findest du einen Artikel (How to build applications with the WebSocket API for Java EE and Jakarta EE), der die Nutzung vorstellt.

Krammer456 
Fragesteller
 19.09.2022, 20:55

Vielen Dank! Ich werds morgen gleich probieren. Kann man einen Apache Webserver und einen Yaws Webserver gleichzeitig laufen lassen. Fals ja, Ist dies schlecht bzw. Hat es nachteile?

0
regex9  19.09.2022, 21:52
@Krammer456

An sich wäre das möglich, doch du müsstest aufpassen, dass beide auf unterschiedliche Adressen (IP / Port) lauschen. Wenn beide auf dem selben Rechner laufen, müssen sie sich natürlich dessen Ressourcen (Arbeitsspeicher, CPU, etc.) teilen. Für Hobbyprojekte / Projekte mit eher wenigen Nutzeranfragen ist das unproblematisch.

0
Krammer456 
Fragesteller
 21.09.2022, 15:33
@regex9

Hallo, ich habe es jetzt versucht, dass ich die Websocketkonfiguration für den Apache Webserver implementiere und anschließend hätte ich den Weg über Cowboy probiert. Ich habe bereits eine Frage bei Stack Overflow erstellt, wo auch Code dabei ist: HTML+Websocket

Wo liegt mein Fehler?

0
regex9  22.09.2022, 06:44
@Krammer456

Lauscht ein Server denn bereits auf den Port 12123 und liefert sicher einen Response auf Anfrage (z.B. ein einfaches HTML-Dokument)? Bevor du den Apache als Proxy einrichtest, würde ich das sicherstellen.

Bei deinen Rewrite-Regeln sind mir drei Punkte aufgefallen, die ich ändern würde.

1) Das Protokoll wird mit zwei Slashes beendet, statt nur einem: wss://.

2) Im Upgrade-Header wäre mit nur einem Wert zu rechnen, also wäre ein expliziter einfacher Stringvergleich passender / sicherer.

RewriteCond ${HTTP:Upgrade} =websocket [NC]

3) Der Zugriff auf HTTP-Header wird in der Dokumentation von Apache stets anders gezeigt (sowohl in Beispielen als auch in der Beschreibung - siehe Punkt 4 unter Other things you should be aware of).

%{HTTP:Connection}

Ich denke, es wäre generell einfacher, es erst einmal ohne Zertifikat und TLS über Port 80 zu testen.

<VirtualHost *:80>
  ServerName your-domain.de

  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined

  RewriteEngine On
  RewriteCond %{HTTP:Upgrade} =websocket [NC]
  RewriteRule /(.*) ws://localhost:12123/$1 [P,L]
  RewriteCond %{HTTP:Upgrade} !=websocket [NC]
  RewriteRule /(.*) http://localhost:12123/$1 [P,L]

  ProxyPassReverse / http://localhost:12123/
</VirtualHost>

Auf den Connection-Header muss man meines Erachtens nicht prüfen, denn der Upgrade-Header wäre im Wert bereits eindeutig.

0
Krammer456 
Fragesteller
 22.09.2022, 07:27
@regex9

Ich habe zuvor den Webserver für SSL eingerichtet und alles hat mit https://.. auf den Port 443 funktioniert. Dies sollte weiterhin, wenn möglich funktionieren. Wenn ich per Handyapp eine HTTPrequest erstelle, welche auf den 443 Port geht, sollte eine response kommen. Vor der Installation des Sockets hats auch problemlos funktioniert. Bzw. Wenn ich die Zeile RewriteRule auskommentiere, dann funktionierts auch immer noch. Auch mit SSL Zertifikat etc. Ich kann mal deine Änderungen zu Hause probieren. Aber ermöglicht es diese Änderung, dass ich auf dem Port 443 die HTML Seiten aufrufen kann und am Port 12123 die Websocket Verbindung machen kann? Das ist was ich machen will. Oder müsste ich hierfür einen neuen VirtualHost anlegen?

Du sagtest oben "Lauscht ein Server den bereits auf Port 12123" Die HTML Anfragen sollten ja weiterhin auf 443 laufen.

0
regex9  22.09.2022, 07:47
@Krammer456
Aber ermöglicht es diese Änderung, dass ich auf dem Port 443 die HTML Seiten aufrufen kann und am Port 12123 die Websocket Verbindung machen kann?

Mein obiges Snippet würde erst einmal keinen Datentransport über wss erlauben.

Du kannst es aber leicht ändern. Tausche die Portnummer 80 gegen 443 aus, ergänze das s für die jeweiligen Protokolle der Adressen und füge die Zertifikatsdirektiven ein.

Du sagtest oben "Lauscht ein Server den bereits auf Port 12123" Die HTML Anfragen sollten ja weiterhin auf 443 laufen.

Dein Apache-Server agiert als Proxy. Das bedeuet, er nimmt HTTP-Anfragen auf Port 80 und 443 an und leitet sie, je nachdem, für welchen Port du nun die VirtualHost-Konfiguration anpasst, an localhost:12123 weiter.

Wenn du also deine Konfiguration für Port 443 setzt und eine Anfrage wie https://your-domain.de/somepage.html an den Server schickst, dann geht diese weiter an https://localhost:12133/somepage.html. Nun muss es natürlich einen Webserver geben, der auf den Host localhost mit dem Port 12133 lauscht und auch antwortet, andernfalls geht die Anfrage ins Leere (und in deinem Serverlog sollte ein Fehler vermerkt werden).

0
Krammer456 
Fragesteller
 22.09.2022, 10:09
@regex9

Ach herje. Das wird ja schon sehr kompliziert. Wie kann ich das nun realisieren, das ich sowohl den Websocket jetzt über Port 12123 erreichen kann, aber dennoch meine HTML/PHP weiterhin über z.b.: https://domain.de/login.php erreichen kann. Der Apache ist ja mein Webserver oder nicht? Wie kann ich das jetzt konfigurieren das er diese Seiten erreichbar macht und wo muss ich die Dateien dann abspeichern? Standardmäßig ist dies ja bei /var/www/Domain

0
regex9  24.09.2022, 00:57
@Krammer456

Ein Proxyserver ist eigentlich dazu da, den tatsächlichen Webserver mit der Webanwendung weiter abzukapseln. Er kümmert sich um das Weiterleiten von Anfragen, das Stellen eines Zertifikats oder Caching.

Davon bin ich bei meinem obigen Snippet auch ausgegangen.

Die Rolle der Anfragenverarbeitung sowohl für HTTP, als auch WS (Request > Response) hätte der Server übernommen, der auf localhost:12123 lauscht. Ob das nun ein IIS-, Tomcat- oder Express-Server wäre, wäre egal, so lange neben HTTP/S auch WebSockets unterstützt werden. Deshalb gibt es für beide Protokolle eine RewriteRule.

Den Apache sowohl als Proxy, als auch Webserver einzusetzen, sollte ebenso klappen. Wie schon geschrieben, gilt der Proxy nach obiger Konfiguration nur für den entsprechenden VirtualHost-Eintrag / Port. Für localhost:12123 benötigst du einen WebSocket-Server.

Die Proxy-Direktiven (ProxyPass, ProxyPassReverse) können zudem auf einen bestimmten Subpfad beschränkt werden. So würde hier

ProxyPass "/example/" "http://other-server.com/"

eine Anfrage an http://your-domain.com/example/index zu http://other-server-com/example/index umgeleitet werden.

Die Direktiven ProxyPass und ProxyRequests (mit dem Wert Off) habe ich im obigen Snippet übrigens vergessen, sehe ich gerade.

Nutze die Dokumentation von Apache zum mod_proxy-Modul.

1
Krammer456 
Fragesteller
 24.09.2022, 18:37
@regex9

Ist dieser Virtualhost dann soweit ok?

<IfModule mod_ssl.c>
<VirtualHost *:443>
    	ServerName ***
  	ServerAdmin webmaster@localhost	
      	DocumentRoot /var/www/***
	
	<Directory /var/www>
		Options -Indexes +FollowSymLinks
		AllowOverride none
		Order allow,deny
		allow from all
	</Directory>	
	
    	ErrorLog ${APACHE_LOG_DIR}/error.log
    	CustomLog ${APACHE_LOG_DIR}/access.log combined

	RewriteEngine on
	RewriteCond %{HTTP:Upgrade} =websocket [NC]
	RewriteRule .* wss://localhost:12123/$1 [P,L]
	ProxyRequests off

	SSLEngine On
        SSLCertificateFile /etc/letsencrypt/live/***/cert.pem
	SSLCertificateKeyFile /etc/letsencrypt/live/***/privkey.pem
	SSLCertificateChainFile /etc/letsencrypt/live/***/chain.pem
</VirtualHost>
</IfModule>

Soweit ich jetzt das richtig verstanden habe, wenn websocket anfragen rein kommen werden diese jetzt durch die RewriteRule auf wss://localhost:12123/$1 weitergeleitet oder?

0
regex9  27.09.2022, 08:56
@Krammer456
(...) wenn websocket anfragen rein kommen werden diese (...) weitergeleitet oder?

Theoretisch ja. Praktisch musst du selbst testen, ob mit dieser Konfiguration alles passt.

0
Krammer456 
Fragesteller
 27.09.2022, 09:05
@regex9

Ja die HTML Seiten sind soweit noch erreichbar und beim Websocket habe ich noch Schwierigkeiten. Bin nicht in der Lage, deine beiden Cowboy skripe zum laufen zu bringen. Hätte noch ne StackOverflow Frage gestellt, aber dort scheint es, als hätte die Community auch nicht die Ahnung von Erlang die ich benötigen würde :). Ich bin schon am überlegen, ob ich die Websocketserver vorerst nicht über c++ realisiere, andererseits denk ich mir, wenn schon, dann richtig das ichs über Erlang realisieren. Wenn man sich die Vorteile ansieht.

0
regex9  27.09.2022, 10:47
@Krammer456
aber dort scheint es, als hätte die Community auch nicht die Ahnung von Erlang die ich benötigen würde

Die Antwort von 7stud ist schon gut, denn sie liefert die richtigen Ansätze.

Die Ausführung von make auf der Konsole erfordert ein entsprechendes Maketool. Der Autor nutzt offensichtlich ein Unix-System, dort ist make bereits integriert. Auf Windows OS kann man sich make via Chocolatey (choco install make) installieren. Die Erlang Shell dürfte aber ebenso ein make-Tool integriert haben. Die Makefile selbst findest du im GitHub-Projekt, sie ist auf die Verzeichnisstruktur des GitHub-Projekts ausgerichtet. Zwingend nutzen musst du sie nicht. Wichtig ist lediglich, das Projekt zu bauen und zu starten. Ob mit einzelnen Befehlen in der Konsole oder via Buildtool / IDE.

IntelliJ kannst du für Erlang-Projekte ebenfalls verwenden. In der JetBrains-Dokumentation wird beschrieben, wie ein Setup aussehen muss.

https://www.jetbrains.com/help/idea/erlang-start-project.html

Bezüglich cowboy_http_handler musst du aufpassen, welche Cowboy-Version du nutzt. Ungefähr ab Version 2 wurden Handler-Namen angepasst. So heißt cowboy_http_handler inzwischen cowboy_handler.

Ich bin schon am überlegen, ob ich die Websocketserver vorerst nicht über c++ realisiere (...)

Nimm den für dich einfacheren Weg. Vorteile einer Technologie bringen dir nur etwas, wenn du in ihr auch bewandert bist und somit weißt, wie du sie für dich einsetzen kannst. Außerdem solltest du eine realistische Einschätzung vornehmen, welche technischen Anforderungen deine Zielanwendung tatsächlich erfüllen muss.

1

Die Frage ist eher, was verhindert das socket.io läuft . Und benutzt du reines JavaScript vom backend oder ist das Cross Origin mit einem Frontendframework .

also bei mir funktioniert socket.io aufm mobil .

aber ich verstehe auch nicht was du mit direkten antworten etc meinst . es scheint mir das du noch zu wenig verständnis hast von der ganzen thematik . auf was soll den die app sonst reagieren ? sorry aber einerseits sagst du , ja es bekommt nachrichten , anderer seits sagst du nein es bekommt keine nachrichten . meinst du push nachrichten im hintergrund oder mit was ist dein problem vergleichbar .

Krammer456 
Fragesteller
 19.09.2022, 16:27
  1. Ich benutze kein JavaScript im Backend. Für die HttpRequests habe ich PHP verwendet. Nun möchte ich den Websocket-Server in Erlang schreiben. Ich habe gelesen, dass viele SocialMedia Konzerne auch im Backend/Socket-Server auf Erlang zurückgreifen.
  2. Soweit ich richtig recherchiert habe funktioniert SocketIO, dass es auf ein event "hört". Wenn z.B. der Server eine "Message" sendet. Jedoch konnte ich bisher noch keinen Weg finden, damit ich mit Erlang einen EventTag z.B. "Message" mit anschließenden "Inhalt" sende.
  3. Ich konnte mit meinem Programm eine Socket (SocketLibrary )Verbindung erstellen:
private void connect(){
    Thread connect = new Thread(new Runnable() {
        @Override
        public void run() {
            Log.e("Socket","Connecting...");
            try{
                s = new Socket(URL,9000);
                Log.e("Socket","Connected!");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });
    connect.start();
}

public Runnable writeToSocket = new Runnable() {
    @Override
    public void run() {
        String message = et.getText().toString();
        byte[] a = message.getBytes(StandardCharsets.UTF_8);
        DataOutputStream dos;

        try {
            dos = new DataOutputStream(s.getOutputStream());
            dos.write(a);

            Log.e("Socket","Writing...");
            InputStream r = s.getInputStream();
            Log.e("Socket","Receiving...");
            int i = r.available();
            byte[] data = new byte[80];
            r.read(data);

            String response = new String(data);
            Log.e("Message",response);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
};

Jedoch habe ich hier nur wenn ich die writeToSocket Funktion aufgerufen habe auch eine Antwort vom Server erhalten. Hier mit getInputStream(); Jedoch war es mir nicht möglich eine bidirektionale Verbindung zu realisieren, bei welcher der Serven von sich aus eine Nachricht an den Client senden kann.

0
TechPech1984  19.09.2022, 16:47
@Krammer456

sendet den dein server überhaupt was ?

sorry mir ist das noch unklar . also du hast ein connect und erhälst z.b. keine begrüßungs message die du aber im server absetzt ?

also der server muss halt in der connect bzw joined clients ein event senden

und dein client muss halt nach connect auf ein event warten .

da gibts viele hürden woran es scheitern kann .

vielleicht solltest du erstmal mit anderen sprachen die grundlagen aufbauen und dich dann an die umsetzung mit java machen . praktisch sollte doch auch ein javascript client mit deinem server reden können . den soviel ich gelesen hab ist erlangen-server compaitble mit socket.io client javascript .

die frage ist also ob du überhaupt im server ein loop hast der einfach für connected clients überhaupt ein emit macht . wie bei einem game server , der ein loop hat, damit er ständig die aktuellen positionen an den client pusht .

ansonsten ist das meist erstmal das frage anwort spiel , client fragt , server antwortet . ohne loop und eben push nachrichten passiert auch nichts. sind mehrere clients connected, kannd er server einbroadcast emiten und allen clients die nachricht zukommen lassen .

und bidirectional hast du ja schon wenn du auf eine frage eine antwort bekommst, sonst wäre ja eh gar keine connect da , den connect heisst quasi standleitung .

0
Krammer456 
Fragesteller
 19.09.2022, 17:51
@TechPech1984

okey, ich probiere es dann mit socketIO noch einmal. Vielleicht habe ich nur den falschen Weg versucht, wenn du sagst es sollte funktionieren. Danke

0