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.
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.
Nº | 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 |