WebSocket ist ein Protokoll, das es ermöglicht, eine interaktive Zwei-Wege-Kommunikationssitzung zwischen dem Client und dem Server zu eröffnen. Es bietet einen Vollduplex-Kommunikationskanal über eine einzige TCP-Verbindung.

Dieses Protokoll definiert eine API, die eine "Socket"-Verbindung zwischen einem Webbrowser und einem Server herstellt. Anstatt langwierige Abfragen durchzuführen, um z. B. Aktualisierungen von einer Livescore-App zu erhalten, können Sie Websockets verwenden, um eine dauerhafte Verbindung zwischen dem Client und dem Server herzustellen. Auf diese Weise aktualisiert sich die Anwendung automatisch, sobald neuere Updates verfügbar sind.

Dadurch wird der Overhead vermieden, der durch das Senden einer zusätzlichen HTTP-Anfrage entsteht, um zu prüfen, ob es neuere Updates gibt.

Client und Server müssen also nur einen Handshake durchführen, und es kann direkt eine dauerhafte Verbindung zwischen den beiden hergestellt und ein bidirektionaler Datentransfer durchgeführt werden.

Websocket

Websocket verwendet denselben TCP-Port wie HTTP, wodurch die meisten Firewall-Beschränkungen umgangen werden können. Standardmäßig verwendet das Websocket-Protokoll Port 80; wenn es zusammen mit TLS läuft, wird standardmäßig Port 443 verwendet. Seine Protokollkennung lautet ws. Wenn wss für die Verschlüsselung verwendet wird, ist die Webadresse des Servers eine URL, wie z.B.:

ws://www.example.com/
wss://www.example.com/

Vorteile von Websocket

  • Weniger Steuerungsaufwand: Nach dem Aufbau der Verbindung, wenn Daten zwischen dem Server und dem Client ausgetauscht werden, ist der für die Protokollsteuerung verwendete Datenpaketkopf relativ klein.
  • Stärkere Echtzeitleistung: Da das Protokoll voll-duplex ist, kann der Server jederzeit aktiv Daten an den Client senden.
  • Beibehaltung des Verbindungsstatus: Im Gegensatz zu HTTP muss bei Websocket zuerst eine Verbindung aufgebaut werden, was es zu einem zustandsabhängigen Protokoll macht, und ein Teil der Zustandsinformationen kann bei der Kommunikation weggelassen werden. Die HTTP-Anfrage muss möglicherweise bei jeder Anfrage Statusinformationen enthalten (z. B. Identitätsauthentifizierung usw.)
  • Bessere Unterstützung von Binärdaten: Websocket definiert binäre Frames, die binäre Inhalte leichter verarbeiten können als HTTP
  • Bessere Kompressionswirkung: Im Vergleich zur HTTP-Komprimierung kann Websocket den Kontext des vorherigen Inhalts mit entsprechender Erweiterungsunterstützung nutzen und die Komprimierungsrate bei der Übertragung ähnlicher Daten erheblich verbessern.

Beispiel 1: Android WebSockets Beispiel

In diesem Tutorial lernen Sie, wie Sie Websockets mit OkHTTP verwenden. Die Url(ws://echo.websocket.org) wird zur Einrichtung von Websockets verwendet.

Schritt 1: Installieren Sie Okhttp

Fügen Sie in Ihrer app-level build.gradle die folgende Implementierungsanweisung hinzu:

implementation 'com.squareup.okhttp3:okhttp:3.6.0'

Schritt 2: Internet-Berechtigung hinzufügen

Fügen Sie in Ihrem Android-Manifest die Internet-Berechtigung wie folgt hinzu:

    <uses-permission android:name="android.permission.INTERNET"/>

Schritt 3: Layout entwerfen

Erstellen Sie ein Layout mit einer Textansicht und einer Schaltfläche. Die Textansicht wird das Ergebnis vom Server anzeigen. Die Schaltfläche hingegen wird die Verbindung initiieren:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/buttonSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="SEND"
        android:layout_marginTop="60dp"
        android:textSize="20sp"/>
    <TextView
        android:id="@+id/textResult"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/buttonSend"
        android:layout_centerHorizontal="true"
        android:textSize="18sp"
        android:layout_marginTop="40dp"/>
</RelativeLayout>

Schritt 4: Code schreiben

Beginnen Sie mit der Erstellung einer Hilfsmethode, um das Ergebnis des Servers in einer Textansicht auszugeben. Dies wird auf dem UI-Thread durchgeführt:

    private void print(final String message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textResult.setText(textResult.getText().toString() + "\n" + message);
            }
        });
    }

Erstellen Sie einen EchoWebListener als innere Klasse. Diese Klasse wird den WebSocketListener erweitern:

    private final class EchoWebSocketListener extends WebSocketListener {
        private static final int CLOSE_STATUS = 1000;
        @Override
        public void onOpen(WebSocket webSocket, Response response) {
            webSocket.send("What's up ?");
            webSocket.send(ByteString.decodeHex("abcd"));
            webSocket.close(CLOSE_STATUS, "Socket Closed !!");
        }
        @Override
        public void onMessage(WebSocket webSocket, String message) {
            print("Receive Message: " + message);
        }
        @Override
        public void onMessage(WebSocket webSocket, ByteString bytes) {
            print("Receive Bytes : " + bytes.hex());
        }
        @Override
        public void onClosing(WebSocket webSocket, int code, String reason) {
            webSocket.close(CLOSE_STATUS, null);
            print("Closing Socket : " + code + " / " + reason);
        }
        @Override
        public void onFailure(WebSocket webSocket, Throwable throwable, Response response) {
            print("Error : " + throwable.getMessage());
        }
    }

Die folgende Methode wird die WebSocket-Verbindung initiieren. Die Klasse OkHTTP Request wird instanziiert und die URL wird an die Methode url() übergeben. Dann wird ein EchoWebSocketListener instanziiert und sowohl das Request-Objekt als auch die EchoWebListener-Instanz an die Methode newWebSocket() übergeben.

Hier ist die vollständige Methode:

    private void start() {
        Request request = new Request.Builder().url("ws://echo.websocket.org").build();
        EchoWebSocketListener listener = new EchoWebSocketListener();
        WebSocket webSocket = mClient.newWebSocket(request, listener);
        mClient.dispatcher().executorService().shutdown();
    }

Hier ist der vollständige Code:

MainActivity.java


import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

public class MainActivity extends AppCompatActivity {

    private Button buttonSend;
    private TextView textResult;
    private OkHttpClient mClient;

    private final class EchoWebSocketListener extends WebSocketListener {
        private static final int CLOSE_STATUS = 1000;
        @Override
        public void onOpen(WebSocket webSocket, Response response) {
            webSocket.send("What's up ?");
            webSocket.send(ByteString.decodeHex("abcd"));
            webSocket.close(CLOSE_STATUS, "Socket Closed !!");
        }
        @Override
        public void onMessage(WebSocket webSocket, String message) {
            print("Receive Message: " + message);
        }
        @Override
        public void onMessage(WebSocket webSocket, ByteString bytes) {
            print("Receive Bytes : " + bytes.hex());
        }
        @Override
        public void onClosing(WebSocket webSocket, int code, String reason) {
            webSocket.close(CLOSE_STATUS, null);
            print("Closing Socket : " + code + " / " + reason);
        }
        @Override
        public void onFailure(WebSocket webSocket, Throwable throwable, Response response) {
            print("Error : " + throwable.getMessage());
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        buttonSend = (Button) findViewById(R.id.buttonSend);
        textResult = (TextView) findViewById(R.id.textResult);
        mClient = new OkHttpClient();
        buttonSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                start();
            }
        });
    }
    private void start() {
        Request request = new Request.Builder().url("ws://echo.websocket.org").build();
        EchoWebSocketListener listener = new EchoWebSocketListener();
        WebSocket webSocket = mClient.newWebSocket(request, listener);
        mClient.dispatcher().executorService().shutdown();
    }
    private void print(final String message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textResult.setText(textResult.getText().toString() + "\n" + message);
            }
        });
    }
}

Referenz

Nachfolgend der Link zum Download.

No. Link
1. Download code
2. Folgen code author

Beispiel 2: Kotlin Android Websocket Beispiel mit Okhttp

Hier ist ein weiteres Android-Websocket-Beispiel, diesmal aber in Kotlin geschrieben. Es verwendet immer noch OkHttp als Netzwerkbibliothek.

Schritt 1: Projekt erstellen

Beginnen Sie mit der Erstellung eines leeren Android Studio-Projekts.

Schritt 2: Abhängigkeiten

Wir werden zwei OkHttp-Bibliotheken installieren:

    implementation 'com.squareup.okhttp3:okhttp:3.12.6'
    implementation 'com.squareup.okhttp3:mockwebserver:3.12.1'

Fügen Sie diese in Ihre app/build.gradle ein und synchronisieren Sie.

Schritt 3: Design Layout

Fügen Sie im Layout Ihrer MainActivity mehrere Buttons und einen Edit-Text wie unten gezeigt ein:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/connectBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="20dp"
        android:layout_marginRight="20dp"
        android : text = " Connect "
        app:layout_constraintRight_toLeftOf="@+id/clientSendBtn"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/clientSendBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android : text = " Send from the client "
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/closeConnectionBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="10dp"
        android : text = " Client is closed "
        app:layout_constraintLeft_toRightOf="@+id/clientSendBtn"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/contentEt"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="10dp"
        android:background="@color/colorGray"
        android:enabled="false"
        android:gravity="top"
        android:padding="5dp"
        android:textColor="@color/colorWhite"
        android:textSize="14sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/clientSendBtn"
        app:layout_constraintVertical_weight="1" />

</androidx.constraintlayout.widget.ConstraintLayout>

Schritt 4: Erstellen Sie einen Message Listener

Dabei handelt es sich um eine Schnittstelle mit mehreren Callbacks, die je nach Status der Verbindung ausgelöst werden, z. B. wenn die Verbindung erfolgreich hergestellt wurde, geschlossen wurde, fehlgeschlagen ist usw:

MessageListener.kt

interface MessageListener {
    fun  onConnectSuccess () // successfully connected
    fun  onConnectFailed () // connection failed
    fun  onClose () // close
    fun onMessage(text: String?)
}

Schritt 5: Erstellen eines Websocket-Managers

Erstellen Sie eine WebSocketManager.kt und fügen Sie die folgenden Importe hinzu:

import  android.util.Log
import okhttp3.*
import okio.ByteString
import  java.util.concurrent.TimeUnit

Erstellen Sie eine Objektklasse WebSocketManager mit den folgenden privaten Feldern;

object  WebSocketManager {
    private val TAG = WebSocketManager::class.java.simpleName
    private  const  val  MAX_NUM  =  5  // Maximum number of reconnections
    private  const  val  MILLIS  =  5000  // Reconnection interval, milliseconds
    private lateinit var client: OkHttpClient
    private lateinit var request: Request
    private lateinit var messageListener: MessageListener
    private lateinit var mWebSocket: WebSocket
    private var isConnect = false
    private var connectNum = 0

Dann die init-Funktion, übergeben Sie die url sowie den MessageListener. Hier initialisieren Sie den OkHTTP-Client:

    fun init(url: String, _messageListener: MessageListener) {
        client = OkHttpClient.Builder()
            .writeTimeout(5, TimeUnit.SECONDS)
            .readTimeout(5, TimeUnit.SECONDS)
            .connectTimeout(10, TimeUnit.SECONDS)
            .build()
        request = Request.Builder().url(url).build()
        messageListener = _messageListener
    }

Nun erstellen Sie eine Funktion zum Verbinden:`

    fun connect() {
        if (isConnect()) {
            Log.i(TAG, "web socket connected")
            return
        }
        client.newWebSocket(request, createListener())
    }

Erstellen Sie auch eine Funktion zum erneuten Verbinden:

    fun reconnect() {
        if (connectNum <= MAX_NUM) {
            try {
                Thread.sleep(MILLIS.toLong())
                connect()
                connectNum++
            } catch (e: InterruptedException) {
                e.printStackTrace ()
            }
        } else {
            Log.i(
                TAG,
                "reconnect over $MAX_NUM,please check url or network"
            )
        }
    }

Wir werden auch Funktionen haben, um eine Nachricht zu senden:

    fun sendMessage(text: String): Boolean {
        return if (!isConnect()) false else mWebSocket.send(text)
    }
    fun sendMessage(byteString: ByteString): Boolean {
        return if (!isConnect()) false else mWebSocket.send(byteString)
    }

Und eine Funktion zum Schließen der Verbindung:

    fun close() {
        if (isConnect()) {
            mWebSocket.cancel()
            mWebSocket.close( 1001 , "The client actively closes the connection " )
        }
    }

Hier ist der vollständige Code:

WebSocketManager.kt

import  android.util.Log
import okhttp3.*
import okio.ByteString
import  java.util.concurrent.TimeUnit

object  WebSocketManager {
    private val TAG = WebSocketManager::class.java.simpleName
    private  const  val  MAX_NUM  =  5  // Maximum number of reconnections
    private  const  val  MILLIS  =  5000  // Reconnection interval, milliseconds
    private lateinit var client: OkHttpClient
    private lateinit var request: Request
    private lateinit var messageListener: MessageListener
    private lateinit var mWebSocket: WebSocket
    private var isConnect = false
    private var connectNum = 0
    fun init(url: String, _messageListener: MessageListener) {
        client = OkHttpClient.Builder()
            .writeTimeout(5, TimeUnit.SECONDS)
            .readTimeout(5, TimeUnit.SECONDS)
            .connectTimeout(10, TimeUnit.SECONDS)
            .build()
        request = Request.Builder().url(url).build()
        messageListener = _messageListener
    }

    /**
     * connect
     */
    fun connect() {
        if (isConnect()) {
            Log.i(TAG, "web socket connected")
            return
        }
        client.newWebSocket(request, createListener())
    }

    /**
     * Reconnection
     */
    fun reconnect() {
        if (connectNum <= MAX_NUM) {
            try {
                Thread.sleep(MILLIS.toLong())
                connect()
                connectNum++
            } catch (e: InterruptedException) {
                e.printStackTrace ()
            }
        } else {
            Log.i(
                TAG,
                "reconnect over $MAX_NUM,please check url or network"
            )
        }
    }

    /**
     * Whether to connect
     */
    fun isConnect(): Boolean {
        return isConnect
    }

    /**
     * send messages
     *
     * @param text string
     * @return boolean
     */
    fun sendMessage(text: String): Boolean {
        return if (!isConnect()) false else mWebSocket.send(text)
    }

    /**
     * send messages
     *
     * @param byteString character set
     * @return boolean
     */
    fun sendMessage(byteString: ByteString): Boolean {
        return if (!isConnect()) false else mWebSocket.send(byteString)
    }

    /**
     * Close connection
     */
    fun close() {
        if (isConnect()) {
            mWebSocket.cancel()
            mWebSocket.close( 1001 , "The client actively closes the connection " )
        }
    }

    private fun createListener(): WebSocketListener {
        return object : WebSocketListener() {
            override fun onOpen(
                webSocket: WebSocket,
                response: Response
            ) {
                super.onOpen(webSocket, response)
                Log.d(TAG, "open:$response")
                mWebSocket = webSocket
                isConnect = response.code() == 101
                if (!isConnect) {
                    reconnect()
                } else {
                    Log.i(TAG, "connect success.")
                    messageListener.onConnectSuccess()
                }
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                super.onMessage(webSocket, text)
                messageListener.onMessage(text)
            }

            override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                super.onMessage(webSocket, bytes)
                messageListener.onMessage(bytes.base64())
            }

            override fun onClosing(
                webSocket: WebSocket,
                code: Int,
                reason: String
            ) {
                super.onClosing(webSocket, code, reason)
                isConnect = false
                messageListener.onClose()
            }

            override fun onClosed(
                webSocket: WebSocket,
                code: Int,
                reason: String
            ) {
                super.onClosed(webSocket, code, reason)
                isConnect = false
                messageListener.onClose()
            }

            override fun onFailure(
                webSocket: WebSocket,
                t: Throwable,
                response: Response?
            ) {
                super.onFailure(webSocket, t, response)
                if (response != null) {
                    Log.i(
                        TAG,
                        "connect failed:" + response.message()
                    )
                }
                Log.i(
                    TAG,
                    "connect failed throwable:" + t.message
                )
                isConnect = false
                messageListener.onConnectFailed()
                reconnect()
            }
        }
    }
}

Schritt 6: Schreiben Sie den Code für die MainActivity

Hier ist der vollständige Code für die MainActivity:

MainActivity.kt

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.concurrent.thread

class MainActivity : AppCompatActivity(), MessageListener {
    private val serverUrl = "ws://192.168.18.145:8086/socketServer/abc"
    override fun onCreate(savedInstanceState: Bundle?) {
        super .onCreate (savedInstanceState)
        setContentView(R.layout.activity_main)
        WebSocketManager.init(serverUrl, this)
        connectBtn.setOnClickListener {
            thread {
                kotlin.run {
                    WebSocketManager.connect()
                }
            }
        }
        clientSendBtn.setOnClickListener {
            if ( WebSocketManager .sendMessage( " Client send " )) {
                addText( " Send from the client \n " )
            }
        }
        closeConnectionBtn.setOnClickListener {
            WebSocketManager.close()
        }
    }

    override fun onConnectSuccess() {
        addText( " Connected successfully \n " )
    }

    override fun onConnectFailed() {
        addText( " Connection failed \n " )
    }

    override fun onClose() {
        addText( " Closed successfully \n " )
    }

    override fun onMessage(text: String?) {
        addText( " Receive message: $text \n " )
    }

    private fun addText(text: String?) {
        runOnUiThread {
            contentEt.text.append(text)
        }
    }

    override fun onDestroy() {
        super .onDestroy ()
        WebSocketManager.close()
    }
}

Run

Kopieren Sie den Code oder laden Sie ihn über den unten stehenden Link herunter, erstellen Sie ihn und führen Sie ihn aus.

Referenz

Hier sind die Referenzlinks:

Nummer Link
1. Download Beispiel
2. Folgen Code-Autor

Categorized in: