Documented WebSocketClient.

Updates after review.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2021-04-22 21:42:14 +02:00
parent 8b10f3ebd5
commit 78dc11b648
4 changed files with 54 additions and 16 deletions

View File

@ -52,6 +52,9 @@ include::../../{doc_code}/org/eclipse/jetty/docs/programming/client/websocket/We
You may create multiple instances of `WebSocketClient`, but typically one instance is enough for most applications.
Creating multiple instances may be necessary for example when you need to specify different configuration parameters for different instances.
For example, you may need different instances when you need to configure the `HttpClient` differently: different transports, different proxies, different cookie stores, different authentications, etc.
WebSocket specific configuration may be typically be given a default value in `WebSocketClient` and then overridden more specifically, see for example xref:pg-websocket-session-configure[this section].
[[pg-client-websocket-stop]]
==== Stopping WebSocketClient

View File

@ -40,7 +40,6 @@ This event is emitted when the WebSocket communication has been successfully est
Applications interested in the connect event receive the WebSocket _session_ so that they can use it to send data to the remote peer.
* The _close_ event.
This event is emitted when the WebSocket communication has been closed.
// TODO: is this event emitted when the application calls Session.close()?
Applications interested in the close event receive a WebSocket status code and an optional close reason message.
* The _error_ event.
This event is emitted when the WebSocket communication encounters a fatal error, such as an I/O error (for example, the network connection has been broken), or a protocol error (for example, the remote peer sends an invalid WebSocket frame).
@ -83,15 +82,41 @@ include::{doc_code}/org/eclipse/jetty/docs/programming/WebSocketDocs.java[tags=s
[[pg-websocket-endpoints-annotated]]
===== Annotated Endpoints
A WebSocket endpoint may annotate methods with `org.eclipse.jetty.websocket.api.annotations.*` annotations to receive WebSocket events:
A WebSocket endpoint may annotate methods with `org.eclipse.jetty.websocket.api.annotations.*` annotations to receive WebSocket events.
Each annotated method may take an optional `Session` argument as its first parameter:
[source,java,indent=0]
----
include::{doc_code}/org/eclipse/jetty/docs/programming/WebSocketDocs.java[tags=annotatedEndpoint]
----
<1> You must annotate the class with the `@WebSocket` annotation to make it an endpoint.
<2> For each event you are interested in, use the correspondent annotation.
<3> Note how methods annotated with `@OnWebSocketMessage` may optionally declare `Session` as first parameter.
<1> Use the `@WebSocket` annotation at the class level to make it a WebSocket endpoint.
<2> Use the `@OnWebSocketConnect` annotation for the _connect_ event.
As this is the first event notified to the endpoint, you can configure the `Session` object.
<3> Use the `@OnWebSocketClose` annotation for the _close_ event.
The method may take an optional `Session` as first parameter.
<4> Use the `@OnWebSocketError` annotation for the _error_ event.
The method may take an optional `Session` as first parameter.
<5> Use the `@OnWebSocketMessage` annotation for the _message_ event, both for textual and binary messages.
The method may take an optional `Session` as first parameter.
[NOTE]
====
For binary messages, you may declare the annotated method with either or these two signatures:
[source,java]
----
@OnWebSocketMessage
public void methodName(byte[] bytes, int offset, int length) { ... }
----
or
[source,java]
----
@OnWebSocketMessage
public void methodName(ByteBuffer buffer) { ... }
----
====
====== Message Streaming Reads
@ -181,6 +206,16 @@ Furthermore, if you have initiated a non-blocking send, you cannot initiate a bl
This requirement is necessary to avoid unbounded buffering that could lead to ``OutOfMemoryError``s.
[CAUTION]
====
We strongly recommend that you follow the condition above.
However, there may be cases where you want to explicitly control the number of outgoing buffered messages using `RemoteEndpoint.setMaxOutgoingFrames(int)`.
Remember that trying to control the number of outgoing buffered messages is very difficult and tricky; you may set `maxOutgoingFrames=4` and have a situation where 6 threads try to concurrently send messages: threads 1 to 4 will be able to successfully buffer their messages, thread 5 may fail, but thread 6 may succeed because one of the previous threads completed its send.
At this point you have an out-of-order message delivery that could be unexpected and very difficult to troubleshoot because it will happen non-deterministically.
====
While non-blocking APIs are more difficult to use, they don't block the sender thread and therefore use less resources, which in turn typically allows for greater scalability under load: with respect to blocking APIs, non-blocking APIs need less resources to cope with the same load.
[[pg-websocket-session-send-stream]]

View File

@ -90,7 +90,7 @@ public class WebSocketDocs
}
@Override
public void onWebSocketBinary(byte[] payload, int offset, int len)
public void onWebSocketBinary(byte[] payload, int offset, int length)
{
// A WebSocket binary message is received.
@ -101,7 +101,7 @@ public class WebSocketDocs
if (pngBytes[i] != payload[offset + i])
return;
}
savePNGImage(payload, offset, len);
savePNGImage(payload, offset, length);
}
}
// end::listenerEndpoint[]
@ -150,7 +150,7 @@ public class WebSocketDocs
session.getRemote().sendString("connected", WriteCallback.NOOP);
}
@OnWebSocketClose // <2>
@OnWebSocketClose // <3>
public void onClose(int statusCode, String reason)
{
// The WebSocket connection is closed.
@ -159,7 +159,7 @@ public class WebSocketDocs
disposeResources();
}
@OnWebSocketError // <2>
@OnWebSocketError // <4>
public void onError(Throwable cause)
{
// The WebSocket connection failed.
@ -171,7 +171,7 @@ public class WebSocketDocs
disposeResources();
}
@OnWebSocketMessage // <2>
@OnWebSocketMessage // <5>
public void onTextMessage(Session session, String message) // <3>
{
// A WebSocket textual message is received.
@ -181,8 +181,8 @@ public class WebSocketDocs
session.getRemote().sendString(message.substring("echo:".length()), WriteCallback.NOOP);
}
@OnWebSocketMessage // <2>
public void onBinaryMessage(byte[] payload, int offset, int len)
@OnWebSocketMessage // <5>
public void onBinaryMessage(byte[] payload, int offset, int length)
{
// A WebSocket binary message is received.
@ -193,7 +193,7 @@ public class WebSocketDocs
if (pngBytes[i] != payload[offset + i])
return;
}
savePNGImage(payload, offset, len);
savePNGImage(payload, offset, length);
}
}
// end::annotatedEndpoint[]
@ -475,7 +475,7 @@ public class WebSocketDocs
{
}
private static void savePNGImage(byte[] payload, int offset, int len)
private static void savePNGImage(byte[] payload, int offset, int length)
{
}

View File

@ -113,7 +113,7 @@ public class WebSocketClientDocs
// receives WebSocket messages from the server.
ClientEndPoint clientEndPoint = new ClientEndPoint();
// The server URI to connect to.
URI serverURI = URI.create("ws://domain.com/path");
URI serverURI = URI.create("wss://domain.com/path");
// Connect the client EndPoint to the server.
CompletableFuture<Session> clientSessionPromise = webSocketClient.connect(clientEndPoint, serverURI);
@ -132,7 +132,7 @@ public class WebSocketClientDocs
webSocketClient.start();
ClientEndPoint clientEndPoint = new ClientEndPoint();
URI serverURI = URI.create("ws://domain.com/path");
URI serverURI = URI.create("wss://domain.com/path");
// Connect the client EndPoint to the server.
CompletableFuture<Session> clientSessionPromise = webSocketClient.connect(clientEndPoint, serverURI);