The process of creation of a WebSocket connection between a a server and a client is as below.
First the client sends an HTTP request to the server with "Connection: Upgrade" and "Upgrade: websocket" headers. Once the server sees above headers it knows that the client wants to make a WebSocket connection.
Then the server sends a response to the client by including above two header parameters.
Websocket communication is done using TCP/IP protocol. So then the current HTTP connection is upgraded to a TCP/IP connection.
In below example, I will show you how to write a simple websocket client and a server. In order to keep this example clearer I purposely avoided introducing best practices and patterns to the code.
1.Server
Create a new maven project. Set the artifact name as WebsocketServer1 and packaging as war. Open the pom.xml and add below configs.
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
</dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
</dependencies>
Now we are going to create the class which acts as the server endpoint. Create a new class and name it as MyServerEndpoint. The content of the class will be as below.
import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/chat")
public class MyServerEndpoint {
public MyServerEndpoint() {
System.out.println("MyServerEndpoint created......");
}
@OnOpen
public void onOpen(Session session) {
System.out.printf("Connection opened....");
try {
session.getBasicRemote().sendText("Your connection accepted...");
} catch (IOException ex) {
ex.printStackTrace();
}
}
@OnClose
public void onClose(Session session) {
System.out.printf("Connection closed....");
}
@OnError
public void onError(Throwable e) {
System.out.printf("Error occurred....");
e.printStackTrace();
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.printf("Message from client: " + message);
try {
session.getBasicRemote().sendText(String.format("Hi client, we got your message '" + message + "'"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/chat")
public class MyServerEndpoint {
public MyServerEndpoint() {
System.out.println("MyServerEndpoint created......");
}
@OnOpen
public void onOpen(Session session) {
System.out.printf("Connection opened....");
try {
session.getBasicRemote().sendText("Your connection accepted...");
} catch (IOException ex) {
ex.printStackTrace();
}
}
@OnClose
public void onClose(Session session) {
System.out.printf("Connection closed....");
}
@OnError
public void onError(Throwable e) {
System.out.printf("Error occurred....");
e.printStackTrace();
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.printf("Message from client: " + message);
try {
session.getBasicRemote().sendText(String.format("Hi client, we got your message '" + message + "'"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Now you can run this web application in tomcat server. Then this endpoint will be deployed and will be listening on below endpoint.
ws://localhost:8080/WebsocketServer1/chat
2.Client
Now I am going to create a websocket client which can communicate with the above server.
Create a new maven project. Set the artifact name as WebsocketClient1 and the packaging as jar.
Add below dependencies to your pom.xml.
Note that javax.websocket-api contains the interfaces for websocket API. Tyrus is an implementation of above API. Tomcat-websocket and jetty-websocket are another such implementations.
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-client</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-container-grizzly</artifactId>
<version>1.1</version>
</dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-client</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-container-grizzly</artifactId>
<version>1.1</version>
</dependency>
Create a new java class as below. This is your websocket client.
import java.net.URI;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
@ClientEndpoint
public class MyClient {
Session userSession = null;
public static void main(String[] args) {
new MyClient().execute();
}
public void execute() {
try {
URI endpointURI = (new URI("ws://localhost:8080/WebsocketServer1/chat"));
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
Session session = container.connectToServer(this, endpointURI);
sendMessage("Hello Server!");
session.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
@OnOpen
public void onOpen(Session userSession) {
this.userSession = userSession;
System.out.println("Websocket connection opened.");
}
@OnClose
public void onClose(Session userSession, CloseReason reason) {
this.userSession = null;
System.out.println("Websocket connection closed.");
}
@OnMessage
public void onMessage(String message) {
System.out.println("From server: " + message);
}
public void sendMessage(String message) {
this.userSession.getAsyncRemote().sendText(message);
}
}
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
@ClientEndpoint
public class MyClient {
Session userSession = null;
public static void main(String[] args) {
new MyClient().execute();
}
public void execute() {
try {
URI endpointURI = (new URI("ws://localhost:8080/WebsocketServer1/chat"));
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
Session session = container.connectToServer(this, endpointURI);
sendMessage("Hello Server!");
session.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
@OnOpen
public void onOpen(Session userSession) {
this.userSession = userSession;
System.out.println("Websocket connection opened.");
}
@OnClose
public void onClose(Session userSession, CloseReason reason) {
this.userSession = null;
System.out.println("Websocket connection closed.");
}
@OnMessage
public void onMessage(String message) {
System.out.println("From server: " + message);
}
public void sendMessage(String message) {
this.userSession.getAsyncRemote().sendText(message);
}
}
Now we are ready to test our server and client. First run the server project on tomcat. Then run the client class. You will see below output in server console.
MyServerEndpoint created......
Connection opened....
Message from client: Hello Server!
Connection closed....
Connection opened....
Message from client: Hello Server!
Connection closed....
And you will see below output in clients console.
Websocket connection opened.
From server: Your connection accepted...
From server: Hi client, we got your message 'Hello Server!'
Websocket connection closed.
From server: Your connection accepted...
From server: Hi client, we got your message 'Hello Server!'
Websocket connection closed.
Below are the annotations used.
@ServerEndpoint - Defines this as a server endpoint which is bound to the path given within brackets
@OnOpen - This method gets executed when a connection between the client and the server is created
@OnClose - This method gets executed when a connection is closed
@OnError - This will be called if an unhandled excetion thrown in other annotated methods.
@OnMessage - This method gets executed when a message is received from other party
@ClientEndpoint - Defines this as a websocket client. In order to the other annotation to work this annotation should be there.
Security:
DO not use unsecured websocket connections(ws://) in pages loaded in HTTPS. Instead, use secured (wss://) connections.
No comments:
Post a Comment