WebSocket é um protocolo que permite abrir uma sessão de comunicação interativa bidirecional entre o cliente e o servidor. Ele fornece canais de comunicação full-duplex em uma única conexão TCP.

Este protocolo define uma API que estabelece uma conexão "socket" entre um navegador da web e um servidor. Em vez de uma longa pesquisa para obter atualizações, por exemplo, de um aplicativo de pontuação ao vivo, você pode usar websockets para criar uma conexão persistente entre o cliente e o servidor. Assim, o aplicativo se atualiza automaticamente sempre que atualizações mais recentes estão disponíveis.

Isso evita a sobrecarga de enviar uma solicitação HTTP adicional para verificar se há atualizações mais recentes.

Assim, o cliente e o servidor precisam apenas completar um handshake, e uma conexão persistente pode ser criada diretamente entre os dois, e a transferência de dados bidirecional é realizada.

Websocket

O Websocket usa a mesma porta TCP que HTTP, que pode ignorar a maioria das restrições de firewall. Por padrão, o protocolo Websocket usa a porta 80; ao executar em cima do TLS, a porta 443 é usada por padrão. Seu identificador de protocolo é ws. Se wss for usado para criptografia, o endereço da Web do servidor será URL, como:

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

Vantagens do Websocket

  • Menos sobrecarga de controle: Depois que a conexão é criada, quando os dados são trocados entre o servidor e o cliente, o cabeçalho do pacote de dados usado para controle de protocolo é relativamente pequeno
  • Desempenho em tempo real mais forte: como o protocolo é full-duplex, o servidor pode enviar dados ativamente para o cliente a qualquer momento
  • Manter o estado da conexão: Ao contrário do HTTP, o Websocket precisa primeiro criar uma conexão, o que o torna um protocolo com estado, e então parte das informações de estado pode ser omitida durante a comunicação. A solicitação HTTP pode precisar carregar informações de status em cada solicitação (como autenticação de identidade etc.)
  • Melhor suporte binário: Websocket define quadros binários, que podem lidar com conteúdo binário mais facilmente do que HTTP
  • Melhor efeito de compactação: Comparado com a compactação HTTP, o Websocket pode usar o contexto do conteúdo anterior com suporte de extensão adequado e pode melhorar significativamente a taxa de compactação ao transferir dados semelhantes.

Exemplo 1: Exemplo de WebSockets do Android

Neste tutorial você aprenderá como usar websockets usando OkHTTP. O url(ws://echo.websocket.org) é usado para configurar websockets.

Etapa 1: Instale o Okhttp

Em seu build.gradle no nível do aplicativo, adicione a seguinte instrução de implementação:

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

Etapa 2: adicionar permissão de Internet

No seu manifesto do Android, adicione a permissão de internet da seguinte forma:

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

Etapa 3: Layout do projeto

Crie um layout com uma visualização de texto e um botão. O textview mostrará o resultado do servidor. O botão, por outro lado, iniciará a conexão:

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>

Etapa 4: escrever código

Comece criando um método auxiliar para imprimir o resultado do servidor em uma visualização de texto. Isso é feito no thread da interface do usuário:

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

Crie um EchoWebListener como uma classe interna. Esta classe estenderá o 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());
        }
    }

O método a seguir iniciará a conexão websocket. A classe OkHTTP Request é instanciada e a url é passada para o método url(). Em seguida, instancie um EchoWebSocketListener e passe o objeto Request e a instância EchoWebListener para o método newWebSocket().

Aqui está o método completo:

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

Aqui está o código completo:

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

Referência

Abaixo segue o link para download.

Link
1. Download código
2. Seguir autor do código

Exemplo 2: Exemplo de Kotlin Android Websocket com Okhttp

Aqui está outro exemplo de websocket android, mas desta vez escrito em Kotlin. Ele ainda usa OkHttp como a biblioteca de rede.

Etapa 1: criar projeto

Comece criando um projeto Android Studio vazio.

Etapa 2: dependências

Vamos instalar duas bibliotecas OkHttp:

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

Adicione aqueles em seu app/build.gradle e sincronize.

Etapa 3: Layout do projeto

No layout do seu MainActivity adicione vários botões e um texto de edição como mostrado abaixo:

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>

Etapa 4: criar um ouvinte de mensagens

Esta será uma interface com vários callbacks gerados dependendo do status da conexão, por exemplo quando conectado com sucesso, fechar, falhar etc:

MessageListener.kt

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

Etapa 5: criar um gerenciador de Websocket

Crie um WebSocketManager.kt e comece adicionando as seguintes importações:

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

Crie uma classe de objeto WebSocketManager com os seguintes campos privados;

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

Então a função init, passa a url assim como o MessageListener. Você inicializa o cliente OkHTTP aqui:

    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
    }

Agora crie uma função para conectar:`

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

Crie também uma função para reconectar:

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

Teremos também funções para enviar uma mensagem:

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

E uma função para fechar a conexão:

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

Aqui está o código completo:

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

Etapa 6: escreva o código MainActivity

Aqui está o código completo para o 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()
    }
}

Correr

Copie o código ou baixe-o no link abaixo, construa e execute.

Referência

Seguem os links de referência:

Número Link
1. Download Exemplo
2. Seguir autor do código

Categorized in: