1616
1717package io .rsocket ;
1818
19- import io .netty .buffer .Unpooled ;
2019import io .rsocket .exceptions .ConnectionErrorException ;
2120import io .rsocket .exceptions .Exceptions ;
2221import io .rsocket .framing .FrameType ;
2322import io .rsocket .internal .LimitableRequestPublisher ;
2423import io .rsocket .internal .UnboundedProcessor ;
2524import java .time .Duration ;
2625import java .util .concurrent .atomic .AtomicBoolean ;
27- import java .util .concurrent .atomic .AtomicInteger ;
2826import java .util .function .Consumer ;
2927import java .util .function .Function ;
30- import javax .annotation .Nullable ;
3128import org .jctools .maps .NonBlockingHashMapLong ;
3229import org .reactivestreams .Publisher ;
3330import org .reactivestreams .Subscriber ;
34- import reactor .core .Disposable ;
3531import reactor .core .publisher .*;
3632
3733/** Client Side of a RSocket socket. Sends {@link Frame}s to a {@link RSocketServer} */
@@ -44,13 +40,10 @@ class RSocketClient implements RSocket {
4440 private final MonoProcessor <Void > started ;
4541 private final NonBlockingHashMapLong <LimitableRequestPublisher > senders ;
4642 private final NonBlockingHashMapLong <UnicastProcessor <Payload >> receivers ;
47- private final AtomicInteger missedAckCounter ;
48-
4943 private final UnboundedProcessor <Frame > sendProcessor ;
44+ private KeepAliveHandler keepAliveHandler ;
5045
51- private @ Nullable Disposable keepAliveSendSub ;
52- private volatile long timeLastTickSentMs ;
53-
46+ /*server requester*/
5447 RSocketClient (
5548 DuplexConnection connection ,
5649 Function <Frame , ? extends Payload > frameDecoder ,
@@ -59,7 +52,7 @@ class RSocketClient implements RSocket {
5952 this (
6053 connection , frameDecoder , errorConsumer , streamIdSupplier , Duration .ZERO , Duration .ZERO , 0 );
6154 }
62-
55+ /*client requester*/
6356 RSocketClient (
6457 DuplexConnection connection ,
6558 Function <Frame , ? extends Payload > frameDecoder ,
@@ -75,24 +68,29 @@ class RSocketClient implements RSocket {
7568 this .started = MonoProcessor .create ();
7669 this .senders = new NonBlockingHashMapLong <>(256 );
7770 this .receivers = new NonBlockingHashMapLong <>(256 );
78- this .missedAckCounter = new AtomicInteger ();
7971
8072 // DO NOT Change the order here. The Send processor must be subscribed to before receiving
8173 this .sendProcessor = new UnboundedProcessor <>();
8274
8375 if (!Duration .ZERO .equals (tickPeriod )) {
84- long ackTimeoutMs = ackTimeout .toMillis ();
85-
86- this .keepAliveSendSub =
87- started
88- .thenMany (Flux .interval (tickPeriod ))
89- .doOnSubscribe (s -> timeLastTickSentMs = System .currentTimeMillis ())
90- .subscribe (
91- i -> sendKeepAlive (ackTimeoutMs , missedAcks ),
92- t -> {
93- errorConsumer .accept (t );
94- connection .dispose ();
95- });
76+ this .keepAliveHandler =
77+ KeepAliveHandler .ofClient (
78+ new KeepAliveHandler .KeepAlive (tickPeriod , ackTimeout , missedAcks ));
79+
80+ started .doOnTerminate (() -> keepAliveHandler .start ()).subscribe ();
81+
82+ keepAliveHandler
83+ .timeout ()
84+ .subscribe (
85+ keepAlive -> {
86+ String message =
87+ String .format ("No keep-alive acks for %d ms" , keepAlive .getTimeoutMillis ());
88+ errorConsumer .accept (new ConnectionErrorException (message ));
89+ connection .dispose ();
90+ });
91+ keepAliveHandler .send ().subscribe (sendProcessor ::onNext );
92+ } else {
93+ keepAliveHandler = null ;
9694 }
9795
9896 connection .onClose ().doFinally (signalType -> cleanup ()).subscribe (null , errorConsumer );
@@ -140,22 +138,6 @@ private void handleSendProcessorCancel(SignalType t) {
140138 }
141139 }
142140
143- private void sendKeepAlive (long ackTimeoutMs , int missedAcks ) {
144- long now = System .currentTimeMillis ();
145- if (now - timeLastTickSentMs > ackTimeoutMs ) {
146- int count = missedAckCounter .incrementAndGet ();
147- if (count >= missedAcks ) {
148- String message =
149- String .format (
150- "Missed %d keep-alive acks with a threshold of %d and a ack timeout of %d ms" ,
151- count , missedAcks , ackTimeoutMs );
152- throw new ConnectionErrorException (message );
153- }
154- }
155-
156- sendProcessor .onNext (Frame .Keepalive .from (Unpooled .EMPTY_BUFFER , true ));
157- }
158-
159141 @ Override
160142 public Mono <Void > fireAndForget (Payload payload ) {
161143 Mono <Void > defer =
@@ -380,17 +362,16 @@ private boolean contains(int streamId) {
380362 }
381363
382364 protected void cleanup () {
365+ if (keepAliveHandler != null ) {
366+ keepAliveHandler .stop ();
367+ }
383368 try {
384369 for (UnicastProcessor <Payload > subscriber : receivers .values ()) {
385370 cleanUpSubscriber (subscriber );
386371 }
387372 for (LimitableRequestPublisher p : senders .values ()) {
388373 cleanUpLimitableRequestPublisher (p );
389374 }
390-
391- if (null != keepAliveSendSub ) {
392- keepAliveSendSub .dispose ();
393- }
394375 } finally {
395376 senders .clear ();
396377 receivers .clear ();
@@ -437,8 +418,8 @@ private void handleStreamZero(FrameType type, Frame frame) {
437418 break ;
438419 }
439420 case KEEPALIVE :
440- if (! Frame . Keepalive . hasRespondFlag ( frame ) ) {
441- timeLastTickSentMs = System . currentTimeMillis ( );
421+ if (keepAliveHandler != null ) {
422+ keepAliveHandler . receive ( frame );
442423 }
443424 break ;
444425 default :
0 commit comments