Java WebSocket
Java programlama dilinde yer alan WebSocket nedir ile başlayarak WebSocket projesi oluşturma ve kullanımı ile ilgili bilgiler yer alıyor.
WebSocket nedir?
WebSocket hakkında detaylı bilgi almak için WebSocket yazıma bakmalısın.
Java WebSocket
Java ile WebSocket sunucusu ve Java tabanlı istemci oluşturmak için JCP tarafından belirlenen JSR 356 şartnamesi kullanılır.
WebSocket HTTP üzerine inşaa edildiğinden dolayı Servlet Container (Tomcat, Jetty vb.) ve Application Server (GlassFish, Payara vb.) tarafından desteklenmektedir.
WebSocket tanımları Java EE javax.websocket, Jakarta EE jakarta.websocket paketinde yer alır.
WebSocket projesi oluşturma
Maven projesi oluşturarak pom.xml dosyasına kullanılacak kütüphanenin eklenmesi yeterlidir.
Hızlıca maven projesi oluşturmak için archetype:generate kullanabiliriz.
mvn archetype:generate
-DgroupId=com.yusufsezer
-DartifactId=JavaWebSocket
-DarchetypeArtifactId=maven-archetype-webapp
-DinteractiveMode=false
Projeyi oluşturduktan sonra pom.xml dosyasına aşağıdaki kütüphaneyi ekleyelim.
Java EE için;
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
Jakarta EE için;
<dependency>
<groupId>jakarta.websocket</groupId>
<artifactId>jakarta.websocket-api</artifactId>
<version>2.1.1</version>
<scope>provided</scope>
</dependency>
NOT: Güncel sürüm için maven depolarına bakmak faydalı olacaktır.
Java WebSocket sunucu veya istemci oluşturma işleminde programsal ve annotations kullanımını destekler.
Annotations hakkında detaylı bilgi almak için Java Annotations yazıma bakmalısın.
Programsal olarak WebSocket sunucusu oluşturma
Programsal olarak WebSocket sunucusu oluşturmak için Endpoint sınıfının kalıtım alınması ve onOpen metodunun override-ezilmesi edilmesi gerekir.
public class EchoEndpoint extends Endpoint {
@Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String message) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException ex) {
System.err.println(ex);
}
}
});
}
}
Soyut onOpen metot imzasında yer alan Session sınıfı kullanarak herhangi bir mesaj geldiğinde yine session sınıfında yer alan getBasicRemote ile istemciye mesaj atılmıştır
WebSocket sınıfı hazırlandıktan sonra sınıfın WebSocket adresine bağlanması için ServerApplicationConfig arayüzünü uygulayan-implement eden sınıf oluşturulur.
public class EchoWebSocketConfig implements ServerApplicationConfig {
@Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses) {
Set<ServerEndpointConfig> configs = new HashSet<>();
ServerEndpointConfig sec = ServerEndpointConfig.Builder
.create(EchoEndpoint.class, "/echo")
.build();
configs.add(sec);
return configs;
}
@Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
return scanned;
}
}
Servlet Container veya Application Server getEndpointConfigs ve getAnnotatedEndpointClasses metotlarını çalıştırarak WebSocket ayarlarını yapar.
Arayüz uygulanarak-implement edilerek kullanılabileceği gibi arayüz içerisinde yer alan Builder sınıfı kullanılabilir.
NOT: Annotations kullanımı programsal kullanıma göre daha kolay olduğundan annotations kullanımı tercih edilmektedir.
NOT2: Hem annotations kullanımı hem de programsal kullanım istendiğinde annotations kullanımını da programsal olarak yönetmek gerekebilir.
Annotations kullanarak WebSocket sunucusu oluşturma
Annotations kullanımı sınıf başına @ServerEndpoint ve gelen mesajların yönetileceği metot başına @OnMessage ifadesini eklemek yeterli olacaktır.
@ServerEndpoint(value = "/echo")
public class EchoEndpoint {
@OnMessage
public String onMessage(Session session, String message) {
return message;
}
}
WebSocket adresi ve diğer ayarlar @ServerEndpoint içerisine yazılır ve arka planda yapılır.
Annotations kullanımda WebSocket durumlarını yönetmek için @OnOpen, @OnMessage, @OnError ve @OnClose annotationları yer alır.
@ServerEndpoint(value = "/echo")
public class EchoEndpoint {
@OnOpen
public void open(Session session, EndpointConfig config) {
System.out.println("Yeni giriş: " + session.getId());
}
@OnMessage
public void message(Session session, String message) {
System.out.println("Yeni mesaj: " + message);
}
@OnError
public void error(Session session, Throwable error) {
System.err.println(session.getId());
System.err.println(error);
}
@OnClose
public void close(Session session, CloseReason closeReason) {
System.out.println(session.getId());
System.out.println(closeReason.getCloseCode().getCode());
System.out.println(closeReason.getReasonPhrase());
}
}
İstemcilere düz metin (String) yerine byte veya özel veri gönderebilir.
Diğer veri türlerini almak ve yönetmek için farklı metot imzaları ile @OnMessage ifadesi tekrar kullanılabilir.
@ServerEndpoint(value = "/echo")
public class EchoEndpoint {
@OnMessage
public void textMessage(Session session, String message) {
System.out.println("Text message: " + message);
}
@OnMessage
public void binaryMessage(Session session, ByteBuffer message) {
System.out.println("Binary message: " + message.toString());
}
@OnMessage
public void pongMessage(Session session, PongMessage message) {
System.out.println("Pong message: " + message.getApplicationData().toString());
}
}
Session
Java WebSocket istemcileri Session arüyüzü ile ifade eder.
Arayüzün bir örneği metotlara parametre olarak geçirilir.
Arayüz içerisindeki bazı metotlar ve açıklamaları aşağıdadır.
close – İstemci WebSocket bağlantısını kapatmak için kullanılır.
addMessageHandler – Programsal kullanımda mesajları yönetmek için kullanılır.
isOpen – İstemci bağlantı durumunu almak için kullanılır.
getId – İstemciye ait benzersiz numarayı almak için kullanılır.
getOpenSessions – Tüm istemcileri almak için kullanılır.
getBasicRemote – getAsyncRemote – RemoteEndpoint arayüzünü uygulayan sınıf döndürerek istemciye veri gönderimi için kullanılır.
getUserProperties – İstemciye ait veri saklamak için kullanılır.
Aşağıdaki örnek kullanımda bir istemciden gelen veri tüm istemcilere gönderilmiştir.
@ServerEndpoint(value = "/echo")
public class EchoEndpoint {
@OnMessage
public void message(Session session, String message) {
session
.getOpenSessions()
.stream()
.filter(p -> p.isOpen() == true)
.forEachOrdered((s) -> {
try {
s.getBasicRemote().sendText(message);
} catch (IOException ex) {
System.err.println(ex);
}
});
}
}
ServerEndpoint
WebSocket ayarları için kullanılır.
value – WebSocket adresini alır.
URI template ile @ServerEndpoint(“/room/{roomName}”) gibi kullanıma sahiptir.
URI template ile kullanımda adresi elde etmek için @PathParam kullanılır.
@OnMessage
public void onMessage(Session session,
String message,
@PathParam("roomName") String roomName) {
// ...
}
subprotocols – Desteklenen alt protokollerin listesini belirlemek için kullanılır.
decoders – Gelen mesajı işleyecek sınıfları belirlemek için kullanılır.
encoders – Giden mesajı işleyecek sınıfları belirlemek için kullanılır.
configurator – WebSocket ayarlarının yapıldığı sınıfı belirlemek için kullanılır.
Decoders – Encoders
WebSocket String veri türü yanında byte ve özel veri türü iletişimini destekler.
Sunucudan veya istemciden gelen-giden farklı veri türlerinin işlenebilmesi için Java programlama diline çevrilmesi gerekebilir.
Bu durum için Decoders-Encoders yapısı kullanılır.
Örneğin; Aşağıdaki Java sınıfı istemciye gönderelim.
public class Person {
long id;
String firstName;
String lastName;
// constructor-get-set
}
Java nesnelerini istemciye göndermek için RemoteEndpoint arayüzüne ait sendObject metodu kullanılır.
@ServerEndpoint(
value = "/echo",
encoders = PersonEncoder.class
)
public class EchoEndpoint {
@OnMessage
public void message(Session session, String message) {
session
.getOpenSessions()
.stream()
.filter(p -> p.isOpen() == true)
.forEachOrdered((s) -> {
try {
Person yusuf = new Person(1, "Yusuf", "SEZER");
s.getBasicRemote().sendObject(yusuf);
} catch (IOException | EncodeException ex) {
System.err.println(ex);
}
});
}
}
Sınıf istemciye gönderildiğinde @ServerEndpoint ifadesindeki encoders ile belirtilen sınıf kullanılarak istemciye gönderilecektir.
Encoder tanımlamak için Encoder.Binary, Encoder.BinaryStream, Encoder.Text ve Encoder.TextStream arayüzleri kullanılır.
İstemciye gönderilecek veri türüne göre arayüz implement edilir.
public class PersonEncoder implements Encoder.Text<Person> {
@Override
public void init(EndpointConfig config) {}
@Override
public void destroy() {}
@Override
public String encode(Person person) throws EncodeException {
return person.getId()
+ " - "
+ person.getFirstName()
+ " - "
+ person.getLastName();
}
}
WebSocket sunucusundan istemciye Person sınıfından bir nesne gönderildiğinde PersonEncoder sınıfı içerisinde yer alan encode metodunun sonucu istemciye gönderilir.
WebSocket istemcisi oluşturma
Java ile oluşturulan WebSocket sunucusunu tarayıcı üzerinden kullanmak için ayrıca kütüphanenin kullanımına ihtiyaç yoktur.
HTML5 WebSocket yazımda yer alan kodlar kullanılabilir.
WebSocket sunucusu için Java tabanlı istemci oluşturmak için WebSocket implementasyonu olan Tyrus kullanılabilir.
Java WebSocket geliştirmek için oldukça sade bir yapı sunar.
Böylece isteğe özel WebSocket sunucusu ve istemcisi mimarisi oluşturmaya imkan verir.
Java WebSocket örneğine buradan ulaşabilirsiniz.
Java Derslerine buradan ulaşabilirsiniz.
Hayırlı günler dilerim.