WebSocket est un protocole qui permet d'ouvrir une session de communication interactive bidirectionnelle entre le client et le serveur. Il fournit un canal de communication full-duplex sur une seule connexion TCP.

Ce protocole définit une API qui établit une connexion "socket" entre un navigateur Web et un serveur. Plutôt que d'interroger longuement une application livescore pour obtenir des mises à jour, par exemple, vous pouvez utiliser les websockets pour créer une connexion persistante entre le client et le serveur. Ainsi, l'application se met automatiquement à jour dès que de nouvelles mises à jour sont disponibles.

Cela permet d'éviter l'envoi d'une requête HTTP supplémentaire pour vérifier si de nouvelles mises à jour sont disponibles.

Ainsi, le client et le serveur n'ont besoin que de compléter une poignée de main, et une connexion persistante peut être créée directement entre les deux, et un transfert de données bidirectionnel effectué.

Websocket

Websocket utilise le même port TCP que HTTP, ce qui permet de contourner la plupart des restrictions des pare-feu. Par défaut, le protocole Websocket utilise le port 80 ; lorsqu'il fonctionne au-dessus de TLS, le port 443 est utilisé par défaut. Son identifiant de protocole est ws. Si wss est utilisé pour le cryptage, l'adresse web du serveur est l'URL, comme :

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

Avantages de Websocket

  • Moins de surcharge de contrôle : Après la création de la connexion, lorsque les données sont échangées entre le serveur et le client, l'en-tête du paquet de données utilisé pour le contrôle du protocole est relativement faible.
  • Meilleures performances en temps réel : Comme le protocole est full-duplex, le serveur peut envoyer activement des données au client à tout moment.
  • Conservation de l'état de la connexion : Contrairement à HTTP, Websocket doit d'abord créer une connexion, ce qui en fait un protocole à état, puis une partie des informations d'état peut être omise lors de la communication. La requête HTTP peut avoir besoin de transporter des informations d'état dans chaque requête (comme l'authentification de l'identité, etc.).
  • Meilleur support binaire : Websocket définit des trames binaires, qui peuvent gérer le contenu binaire plus facilement que HTTP.
  • Meilleur effet de compression : Par rapport à la compression HTTP, Websocket peut utiliser le contexte du contenu précédent avec un support d'extension approprié, et peut améliorer considérablement le taux de compression lors du transfert de données similaires.

Exemple 1 : Exemple de WebSockets Android

Dans ce tutoriel, vous allez apprendre à utiliser les websockets en utilisant OkHTTP. L'url(ws://echo.websocket.org) est utilisée pour configurer les websockets.

Etape 1 : Installer Okhttp

Dans votre build.gradle au niveau de l'application, ajoutez l'instruction d'implémentation suivante :

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

Étape 2 : Ajouter la permission Internet

Dans votre manifeste android, ajoutez la permission internet comme suit :

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

Étape 3 : Conception de la mise en page

Créez une mise en page avec une vue de texte et un bouton. La vue de texte montrera le résultat du serveur. Le bouton, quant à lui, initiera la connexion :

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>

Étape 4 : Écrire du code

Commencez par créer une méthode d'aide pour imprimer le résultat du serveur sur un textview. Ceci est fait sur le thread de l'interface utilisateur :

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

Créez un EchoWebListener comme classe interne. Cette classe va étendre le WebSocketListener :

    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());
        }
    }

La méthode suivante va initier la connexion websocket. La classe OkHTTP Request est instanciée et l'url est passée à la méthode url(). Ensuite, on instancie un EchoWebSocketListener et on passe l'objet Request et l'instance EchoWebListener à la méthode newWebSocket().

Voici la méthode complète :

    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();
    }

Voici le code complet :

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);
            }
        });
    }
}

Référence

Voici le lien de téléchargement.

No. Lien
1. Télécharger code
2. Suivre code auteur

Exemple 2 : Exemple de websocket Android en Kotlin avec Okhttp

Voici un autre exemple d'android websocket mais cette fois-ci écrit en Kotlin. Il utilise toujours OkHttp comme bibliothèque réseau.

Étape 1 : Créer le projet

Commencez par créer un projet vide Android Studio.

Étape 2 : Dépendances

Nous allons installer deux bibliothèques OkHttp :

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

Ajoutez-les dans votre app/build.gradle et synchronisez.

Step 3 : Conception de la mise en page

Dans le layout de votre MainActivity, ajoutez plusieurs boutons et un edittext comme indiqué ci-dessous :

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>

Step 4 : Créer un récepteur de messages

Il s'agira d'une interface avec plusieurs callbacks déclenchés en fonction de l'état de la connexion, par exemple en cas de connexion réussie, de fermeture, d'échec, etc :

MessageListener.kt

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

Étape 5 : Créer un gestionnaire de Websocket

Créez un WebSocketManager.kt puis commencez par ajouter les importations suivantes :

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

Créez une classe objet WebSocketManager avec les champs privés suivants ;

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

Puis la fonction init, passez l'url ainsi que le MessageListener. Vous initialisez le client OkHTTP ici :

    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
    }

Maintenant, créez une fonction pour se connecter :`

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

Créez également une fonction pour se reconnecter :

    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"
            )
        }
    }

Nous aurons aussi des fonctions pour envoyer un message :

    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)
    }

Et une fonction pour fermer la connexion :

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

Voici le code complet :

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()
            }
        }
    }
}

Etape 6 : Ecrire le code de l'activité principale (MainActivity)

Voici le code complet de la 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()
    }
}

Exécuter

Copiez le code ou téléchargez-le dans le lien ci-dessous, construisez et exécutez.

Référence

Voici les liens de référence :

Numéro Lien
1. Télécharger Exemple
2. Suivre auteur du code

Catégorisé: