Panduan untuk Java API untuk WebSocket

1. Gambaran keseluruhan

WebSocket memberikan alternatif kepada pembatasan komunikasi yang cekap antara pelayan dan penyemak imbas web dengan menyediakan komunikasi pelanggan / pelayan dwi-arah, dupleks penuh, masa nyata. Pelayan boleh menghantar data kepada pelanggan pada bila-bila masa. Kerana ia berjalan melalui TCP, ia juga menyediakan komunikasi tahap rendah latensi rendah dan mengurangkan overhead setiap mesej .

Dalam artikel ini, kita akan melihat Java API for WebSockets dengan membuat aplikasi seperti chat.

2. JSR 356

JSR 356 atau Java API untuk WebSocket, menentukan API yang dapat digunakan oleh pengembang Java untuk mengintegrasikan WebSockets dengan aplikasi mereka - baik di sisi pelayan dan juga di sisi klien Java.

API Java ini menyediakan komponen sisi pelayan dan pelanggan:

  • Pelayan : semua yang ada dalam pakej javax.websocket.server .
  • Pelanggan : kandungan pakej javax.websocket , yang terdiri daripada API sisi klien dan juga perpustakaan umum untuk pelayan dan pelanggan.

3. Membina Sembang Menggunakan WebSockets

Kami akan membina aplikasi seperti sembang yang sangat sederhana. Mana-mana pengguna akan dapat membuka sembang dari penyemak imbas mana pun, menaip namanya, masuk ke dalam sembang dan mula berkomunikasi dengan semua orang yang berhubung dengan sembang tersebut.

Kita akan mulakan dengan menambahkan kebergantungan terkini ke fail pom.xml :

 javax.websocket javax.websocket-api 1.1 

Versi terkini boleh didapati di sini.

Untuk menukar Objek Java menjadi representasi JSON mereka dan sebaliknya, kami akan menggunakan Gson:

 com.google.code.gson gson 2.8.0 

Versi terbaru boleh didapati di repositori Maven Central.

3.1. Konfigurasi Titik Akhir

Terdapat dua cara untuk mengkonfigurasi titik akhir: berasaskan anotasi dan berasaskan peluasan. Anda boleh melanjutkan kelas javax.websocket.Endpoint atau menggunakan anotasi tahap kaedah khusus. Oleh kerana model anotasi membawa kepada kod yang lebih bersih berbanding dengan model terprogram, anotasi telah menjadi pilihan pengkodan konvensional. Dalam kes ini, acara kitaran hayat titik akhir WebSocket dikendalikan oleh anotasi berikut:

  • @ServerEndpoint: Jika dihiasi dengan @ServerEndpoint, wadah memastikan ketersediaan kelas sebagai pelayan WebSocket yang mendengarkan ruang URI tertentu
  • @ClientEndpoint : Kelas yang dihiasi dengan anotasi ini dianggap sebagai pelanggan WebSocket
  • @OnOpen : Kaedah Java dengan @OnOpen dipanggil oleh wadah semasa sambungan WebSocket baru dimulakan
  • @OnMessage : Kaedah Java, dianotasi dengan @OnMessage, menerima maklumat dari wadah WebSocket ketika mesej dihantar ke titik akhir
  • @OnError : Kaedah dengan @OnError dipanggil apabila terdapat masalah dengan komunikasi
  • @OnClose : Digunakan untuk menghias kaedah Java yang dipanggil oleh wadah ketika sambungan WebSocket ditutup

3.2. Menulis Titik Akhir Pelayan

Kami menyatakan titik akhir pelayan WebSocket kelas Java dengan memberi anotasi dengan @ServerEndpoint . Kami juga menentukan URI di mana titik akhir digunakan. URI didefinisikan secara relatif ke akar wadah pelayan dan mesti dimulakan dengan garis miring ke hadapan:

@ServerEndpoint(value = "/chat/{username}") public class ChatEndpoint { @OnOpen public void onOpen(Session session) throws IOException { // Get session and WebSocket connection } @OnMessage public void onMessage(Session session, Message message) throws IOException { // Handle new messages } @OnClose public void onClose(Session session) throws IOException { // WebSocket connection closes } @OnError public void onError(Session session, Throwable throwable) { // Do error handling here } }

Kod di atas adalah kerangka titik akhir pelayan untuk aplikasi seperti sembang kami. Seperti yang anda lihat, kami mempunyai 4 anotasi yang dipetakan mengikut kaedah masing-masing. Di bawah ini anda dapat melihat pelaksanaan kaedah tersebut:

@ServerEndpoint(value="/chat/{username}") public class ChatEndpoint { private Session session; private static Set chatEndpoints = new CopyOnWriteArraySet(); private static HashMap users = new HashMap(); @OnOpen public void onOpen( Session session, @PathParam("username") String username) throws IOException { this.session = session; chatEndpoints.add(this); users.put(session.getId(), username); Message message = new Message(); message.setFrom(username); message.setContent("Connected!"); broadcast(message); } @OnMessage public void onMessage(Session session, Message message) throws IOException { message.setFrom(users.get(session.getId())); broadcast(message); } @OnClose public void onClose(Session session) throws IOException { chatEndpoints.remove(this); Message message = new Message(); message.setFrom(users.get(session.getId())); message.setContent("Disconnected!"); broadcast(message); } @OnError public void onError(Session session, Throwable throwable) { // Do error handling here } private static void broadcast(Message message) throws IOException, EncodeException { chatEndpoints.forEach(endpoint -> { synchronized (endpoint) { try { endpoint.session.getBasicRemote(). sendObject(message); } catch (IOException | EncodeException e) { e.printStackTrace(); } } }); } }

Apabila pengguna baru log masuk ( @OnOpen ) segera dipetakan ke struktur data pengguna aktif. Kemudian, mesej dibuat dan dihantar ke semua titik akhir menggunakan kaedah siaran .

Kaedah ini juga digunakan setiap kali mesej baru dikirim ( @OnMessage ) oleh mana-mana pengguna yang terhubung - ini adalah tujuan utama perbincangan .

Sekiranya pada suatu ketika berlaku ralat, kaedah dengan anotasi @OnError menanganinya. Anda boleh menggunakan kaedah ini untuk mencatat maklumat mengenai ralat dan membersihkan titik akhir.

Akhirnya, apabila pengguna tidak lagi tersambung ke sembang, kaedah @OnClose membersihkan titik akhir dan menyiarkan kepada semua pengguna bahawa pengguna telah terputus.

4. Jenis Mesej

Spesifikasi WebSocket menyokong dua format data on-wire - teks dan binari. API menyokong kedua format ini, menambahkan kemampuan untuk bekerja dengan objek Java dan pesan pemeriksaan kesihatan (ping-pong) seperti yang ditentukan dalam spesifikasi:

  • Teks : Sebarang data teks ( java.lang.String , primitif atau kelas pembungkus yang setara)
  • Perduaan : Data binari (contohnya audio, gambar dll) yang diwakili oleh java.nio.ByteBuffer atau byte [] (array byte)
  • Objek Java : API memungkinkan untuk bekerja dengan perwakilan asli (objek Java) dalam kod anda dan menggunakan transformer tersuai (pengekod / penyahkod) untuk mengubahnya menjadi format on-wire yang serasi (teks, binari) yang dibenarkan oleh protokol WebSocket
  • Ping-Pong : Javax.websocket.PongMessage adalah pengakuan yang dihantar oleh rakan sebaya WebSocket sebagai tindak balas kepada permintaan pemeriksaan kesihatan (ping)

Untuk aplikasi kami, kami akan menggunakan Java Objects. Kami akan membuat kelas untuk pengekodan dan penyahkodan mesej.

4.1. Pengekod

Pengekod mengambil objek Java dan menghasilkan representasi khas yang sesuai untuk penghantaran sebagai mesej seperti JSON, XML atau representasi binari. Encoder boleh digunakan dengan melaksanakan Encoder.Text atau Encoder.Barm antaramuka.

Dalam kod di bawah ini kita menentukan kelas Mesej yang akan dikodkan dan dalam kaedah pengekodan kita menggunakan Gson untuk mengekod objek Java ke JSON:

public class Message { private String from; private String to; private String content; //standard constructors, getters, setters }
public class MessageEncoder implements Encoder.Text { private static Gson gson = new Gson(); @Override public String encode(Message message) throws EncodeException { return gson.toJson(message); } @Override public void init(EndpointConfig endpointConfig) { // Custom initialization logic } @Override public void destroy() { // Close resources } }

4.2. Penyahkod

Decoder adalah kebalikan dari encoder dan digunakan untuk mengubah data kembali menjadi objek Java. Dekoder boleh dilaksanakan menggunakan Decoder.Text atau Decoder.Binary muka.

Seperti yang kita lihat dengan pengekod, kaedah penyahkodan adalah di mana kita mengambil JSON yang diambil dalam mesej yang dikirim ke titik akhir dan menggunakan Gson untuk mengubahnya ke kelas Java yang disebut Mesej:

public class MessageDecoder implements Decoder.Text { private static Gson gson = new Gson(); @Override public Message decode(String s) throws DecodeException { return gson.fromJson(s, Message.class); } @Override public boolean willDecode(String s) { return (s != null); } @Override public void init(EndpointConfig endpointConfig) { // Custom initialization logic } @Override public void destroy() { // Close resources } }

4.3. Menetapkan Encoder dan Decoder di Endpoint Server

Mari satukan semuanya dengan menambahkan kelas yang dibuat untuk pengekodan dan penyahkodan data pada anotasi peringkat kelas @ServerEndpoint :

@ServerEndpoint( value="/chat/{username}", decoders = MessageDecoder.class, encoders = MessageEncoder.class )

Setiap kali mesej dihantar ke titik akhir, ia secara automatik akan ditukar menjadi objek JSON atau Java.

5. Kesimpulan

Dalam artikel ini, kami melihat apa itu Java API untuk WebSockets dan bagaimana ia dapat membantu kami membina aplikasi seperti sembang masa nyata ini.

Kami melihat dua model pengaturcaraan untuk membuat titik akhir: anotasi dan programatik. Kami menentukan titik akhir menggunakan model anotasi untuk aplikasi kami bersama dengan kaedah kitaran hidup.

Juga, untuk dapat berkomunikasi berulang-alik antara pelayan dan klien, kami melihat bahawa kami memerlukan pengekod dan penyahkod untuk menukar objek Java ke JSON dan sebaliknya.

JSR 356 API sangat mudah dan model pengaturcaraan berdasarkan anotasi menjadikannya sangat mudah untuk membina aplikasi WebSocket.

Untuk menjalankan aplikasi yang kita bina dalam contoh, yang perlu kita lakukan adalah menyebarkan fail perang di pelayan web dan pergi ke URL: // localhost: 8080 / java-websocket /. Anda boleh mendapatkan pautan ke repositori di sini.