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