3. Exemples
Cette section donne un certain nombre d'exemples courts avec des flux de messages pour un GET par blocs, et pour un PUT ou un POST. Ces exemples démontrent le fonctionnement de base, le fonctionnement en présence de retransmissions et des exemples pour le fonctionnement de la négociation de la taille de bloc.
Dans tous ces exemples, une option Block est affichée de manière décomposée indiquant le type d'option Block (1 ou 2) suivi de deux points, puis le numéro de bloc (NUM), le bit more (M) et l'exposant de la taille de bloc (2**(SZX+4)) séparés par des barres obliques. Par exemple, une valeur d'option Block2 de 33 serait affichée sous la forme 2:2/0/32) et une valeur d'option Block1 de 59 serait affichée sous la forme 1:3/1/128.
Comme dans [RFC7252], "MID" est utilisé comme abréviation pour "Message ID" (ID de message).
3.1. Exemples Block2
Le premier exemple (Figure 2) montre une requête GET qui est divisée en trois blocs. Le serveur propose une taille de bloc de 128, et le client accepte. Les deux premiers ACK contiennent une charge utile de 128 octets chacun, et le troisième ACK contient une charge utile comprise entre 1 et 128 octets.
CLIENT SERVER
| |
| CON [MID=1234], GET, /status ------> |
| |
| <------ ACK [MID=1234], 2.05 Content, 2:0/1/128 |
| |
| CON [MID=1235], GET, /status, 2:1/0/128 ------> |
| |
| <------ ACK [MID=1235], 2.05 Content, 2:1/1/128 |
| |
| CON [MID=1236], GET, /status, 2:2/0/128 ------> |
| |
| <------ ACK [MID=1236], 2.05 Content, 2:2/0/128 |
Figure 2 : GET par blocs simple
Dans le deuxième exemple (Figure 3), le client anticipe le transfert par blocs (par exemple, en raison d'une indication de taille dans la description link-format [RFC6690]) et envoie une proposition de taille de bloc. Tous les messages ACK sauf le dernier portent 64 octets de charge utile ; le dernier en porte entre 1 et 64.
CLIENT SERVER
| |
| CON [MID=1234], GET, /status, 2:0/0/64 ------> |
| |
| <------ ACK [MID=1234], 2.05 Content, 2:0/1/64 |
| |
| CON [MID=1235], GET, /status, 2:1/0/64 ------> |
| |
| <------ ACK [MID=1235], 2.05 Content, 2:1/1/64 |
: :
: ... :
: :
| CON [MID=1238], GET, /status, 2:4/0/64 ------> |
| |
| <------ ACK [MID=1238], 2.05 Content, 2:4/1/64 |
| |
| CON [MID=1239], GET, /status, 2:5/0/64 ------> |
| |
| <------ ACK [MID=1239], 2.05 Content, 2:5/0/64 |
Figure 3 : GET par blocs avec négociation précoce
Dans le troisième exemple (Figure 4), le client est surpris par la nécessité d'un transfert par blocs, et mécontent de la taille choisie unilatéralement par le serveur. Comme il n'a pas envoyé de proposition de taille initialement, la négociation n'influence la taille qu'à partir du deuxième échange de messages. Puisque le client a déjà obtenu le premier et le deuxième bloc de 64 octets dans le premier échange de 128 octets, il continue en demandant le troisième bloc de 64 octets ("2/0/64"). Rien de tout cela n'est (ni ne doit être) compris par le serveur, qui répond simplement aux requêtes du mieux qu'il peut.
CLIENT SERVER
| |
| CON [MID=1234], GET, /status ------> |
| |
| <------ ACK [MID=1234], 2.05 Content, 2:0/1/128 |
| |
| CON [MID=1235], GET, /status, 2:2/0/64 ------> |
| |
| <------ ACK [MID=1235], 2.05 Content, 2:2/1/64 |
| |
| CON [MID=1236], GET, /status, 2:3/0/64 ------> |
| |
| <------ ACK [MID=1236], 2.05 Content, 2:3/1/64 |
| |
| CON [MID=1237], GET, /status, 2:4/0/64 ------> |
| |
| <------ ACK [MID=1237], 2.05 Content, 2:4/1/64 |
| |
| CON [MID=1238], GET, /status, 2:5/0/64 ------> |
| |
| <------ ACK [MID=1238], 2.05 Content, 2:5/0/64 |
Figure 4 : GET par blocs avec négociation tardive
Dans tous ces cas (et les suivants), les retransmissions sont gérées par la couche d'échange de messages CoAP, elles n'influencent donc pas les opérations de bloc (Figures 5 et 6).
CLIENT SERVER
| |
| CON [MID=1234], GET, /status ------> |
| |
| <------ ACK [MID=1234], 2.05 Content, 2:0/1/128 |
| |
| CON [MID=1235], GE///////////////////////// |
| |
| (timeout) |
| |
| CON [MID=1235], GET, /status, 2:2/0/64 ------> |
| |
| <------ ACK [MID=1235], 2.05 Content, 2:2/1/64 |
: :
: ... :
: :
| CON [MID=1238], GET, /status, 2:5/0/64 ------> |
| |
| <------ ACK [MID=1238], 2.05 Content, 2:5/0/64 |
Figure 5 : GET par blocs avec négociation tardive et CON perdu
CLIENT SERVER
| |
| CON [MID=1234], GET, /status ------> |
| |
| <------ ACK [MID=1234], 2.05 Content, 2:0/1/128 |
| |
| CON [MID=1235], GET, /status, 2:2/0/64 ------> |
| |
| //////////////////////////////////tent, 2:2/1/64 |
| |
| (timeout) |
| |
| CON [MID=1235], GET, /status, 2:2/0/64 ------> |
| |
| <------ ACK [MID=1235], 2.05 Content, 2:2/1/64 |
: :
: ... :
: :
| CON [MID=1238], GET, /status, 2:5/0/64 ------> |
| |
| <------ ACK [MID=1238], 2.05 Content, 2:5/0/64 |
Figure 6 : GET par blocs avec négociation tardive et ACK perdu
3.2. Exemples Block1
Les exemples suivants démontrent un échange PUT ; un échange POST est identique, avec des exigences différentes en matière d'atomicité/idempotence. Notez que, comme pour GET, les réponses aux requêtes qui ont un bit more dans l'option Block1 de la requête sont provisoires et portent le code de réponse 2.31 (Continue) ; seule la réponse finale indique au client que le PUT a réussi.
CLIENT SERVER
| |
| CON [MID=1234], PUT, /options, 1:0/1/128 ------> |
| |
| <------ ACK [MID=1234], 2.31 Continue, 1:0/1/128 |
| |
| CON [MID=1235], PUT, /options, 1:1/1/128 ------> |
| |
| <------ ACK [MID=1235], 2.31 Continue, 1:1/1/128 |
| |
| CON [MID=1236], PUT, /options, 1:2/0/128 ------> |
| |
| <------ ACK [MID=1236], 2.04 Changed, 1:2/0/128 |
Figure 7 : PUT par blocs atomique simple
Un serveur sans état qui construit/met à jour simplement la ressource sur place (sans état) peut l'indiquer en ne définissant pas le bit more dans la réponse (Figure 8) ; dans ce cas, les codes de réponse sont valides séparément pour chaque bloc mis à jour. Ceci n'est bien sûr un comportement acceptable du serveur que si l'incohérence potentielle présente pendant l'exécution de la séquence d'échange de messages ne conduit pas à des problèmes, par exemple parce que la ressource en cours de création ou de modification n'est pas encore ou pas actuellement utilisée.
CLIENT SERVER
| |
| CON [MID=1234], PUT, /options, 1:0/1/128 ------> |
| |
| <------ ACK [MID=1234], 2.04 Changed, 1:0/0/128 |
| |
| CON [MID=1235], PUT, /options, 1:1/1/128 ------> |
| |
| <------ ACK [MID=1235], 2.04 Changed, 1:1/0/128 |
| |
| CON [MID=1236], PUT, /options, 1:2/0/128 ------> |
| |
| <------ ACK [MID=1236], 2.04 Changed, 1:2/0/128 |
Figure 8 : PUT par blocs sans état simple
Enfin, un serveur recevant un PUT ou un POST par blocs peut vouloir indiquer une préférence pour une taille de bloc plus petite (Figure 9). Dans ce cas, le client DEVRAIT continuer avec une taille de bloc plus petite ; s'il le fait, il DOIT ajuster le numéro de bloc pour compter correctement dans cette taille plus petite.
CLIENT SERVER
| |
| CON [MID=1234], PUT, /options, 1:0/1/128 ------> |
| |
| <------ ACK [MID=1234], 2.31 Continue, 1:0/1/32 |
| |
| CON [MID=1235], PUT, /options, 1:4/1/32 ------> |
| |
| <------ ACK [MID=1235], 2.31 Continue, 1:4/1/32 |
| |
| CON [MID=1236], PUT, /options, 1:5/1/32 ------> |
| |
| <------ ACK [MID=1235], 2.31 Continue, 1:5/1/32 |
| |
| CON [MID=1237], PUT, /options, 1:6/0/32 ------> |
| |
| <------ ACK [MID=1236], 2.04 Changed, 1:6/0/32 |
Figure 9 : PUT par blocs atomique simple avec négociation
3.3. Combinaison de Block1 et Block2
Les options Block peuvent être utilisées dans les deux sens d'un même échange. L'exemple suivant démontre une requête POST par blocs, résultant en une réponse par blocs séparée.
CLIENT SERVER
| |
| CON [MID=1234], POST, /soap, 1:0/1/128 ------> |
| |
| <------ ACK [MID=1234], 2.31 Continue, 1:0/1/128 |
| |
| CON [MID=1235], POST, /soap, 1:1/1/128 ------> |
| |
| <------ ACK [MID=1235], 2.31 Continue, 1:1/1/128 |
| |
| CON [MID=1236], POST, /soap, 1:2/0/128 ------> |
| |
| <------ ACK [MID=1236], 2.04 Changed, 2:0/1/128, 1:2/0/128 |
| |
| CON [MID=1237], POST, /soap, 2:1/0/128 ------> |
| (no payload for requests with Block2 with NUM != 0) |
| (could also do late negotiation by requesting, |
| e.g., 2:2/0/64) |
| |
| <------ ACK [MID=1237], 2.04 Changed, 2:1/1/128 |
| |
| CON [MID=1238], POST, /soap, 2:2/0/128 ------> |
| |
| <------ ACK [MID=1238], 2.04 Changed, 2:2/1/128 |
| |
| CON [MID=1239], POST, /soap, 2:3/0/128 ------> |
| |
| <------ ACK [MID=1239], 2.04 Changed, 2:3/0/128 |
Figure 10 : POST par blocs atomique avec réponse par blocs
Ce modèle prévoit une entrée de négociation précoce pour le transfert par blocs Block2, comme indiqué ci-dessous.
CLIENT SERVER
| |
| CON [MID=1234], POST, /soap, 1:0/1/128 ------> |
| |
| <------ ACK [MID=1234], 2.31 Continue, 1:0/1/128 |
| |
| CON [MID=1235], POST, /soap, 1:1/1/128 ------> |
| |
| <------ ACK [MID=1235], 2.31 Continue, 1:1/1/128 |
| |
| CON [MID=1236], POST, /soap, 1:2/0/128, 2:0/0/64 ------> |
| |
| <------ ACK [MID=1236], 2.04 Changed, 1:2/0/128, 2:0/1/64 |
| |
| CON [MID=1237], POST, /soap, 2:1/0/64 ------> |
| (no payload for requests with Block2 with NUM != 0) |
| |
| <------ ACK [MID=1237], 2.04 Changed, 2:1/1/64 |
| |
| CON [MID=1238], POST, /soap, 2:2/0/64 ------> |
| |
| <------ ACK [MID=1238], 2.04 Changed, 2:2/1/64 |
| |
| CON [MID=1239], POST, /soap, 2:3/0/64 ------> |
| |
| <------ ACK [MID=1239], 2.04 Changed, 2:3/0/64 |
Figure 11 : POST par blocs atomique avec réponse par blocs,
Négociation précoce
3.4. Combinaison de Observe et Block2
Dans l'exemple suivant, le serveur envoie d'abord une réponse directe (numéro de séquence Observe 62350) à la requête GET initiale (le transfert par blocs résultant est comme dans la Figure 4 et a donc été omis). Le deuxième transfert est démarré par une notification 2.05 qui contient juste le premier bloc (numéro de séquence Observe 62354) ; le client continue ensuite pour obtenir le reste des blocs.
CLIENT SERVER
| |
+----->| Header: GET 0x41011636
| GET | Token: 0xfb
| | Uri-Path: status-icon
| | Observe: (empty)
| |
|<-----+ Header: 2.05 0x61451636
| 2.05 | Token: 0xfb
| | Block2: 0/1/128
| | Observe: 62350
| | ETag: 6f00f38e
| | Payload: [128 bytes]
| |
| | (Usual GET transfer left out)
...
| | (Notification of first block)
| |
|<-----+ Header: 2.05 0x4145af9c
| 2.05 | Token: 0xfb
| | Block2: 0/1/128
| | Observe: 62354
| | ETag: 6f00f392
| | Payload: [128 bytes]
| |
+- - ->| Header: 0x6000af9c
| |
| | (Retrieval of remaining blocks)
| |
+----->| Header: GET 0x41011637
| GET | Token: 0xfc
| | Uri-Path: status-icon
| | Block2: 1/0/128
| |
|<-----+ Header: 2.05 0x61451637
| 2.05 | Token: 0xfc
| | Block2: 1/1/128
| | ETag: 6f00f392
| | Payload: [128 bytes]
| |
+----->| Header: GET 0x41011638
| GET | Token: 0xfc
| | Uri-Path: status-icon
| | Block2: 2/0/128
| |
|<-----+ Header: 2.05 0x61451638
| 2.05 | Token: 0xfc
| | Block2: 2/0/128
| | ETag: 6f00f392
| | Payload: [53 bytes]
Figure 12 : Séquence Observe avec réponse par blocs
(Notez que le choix du jeton 0xfc dans cet exemple est arbitraire ; les jetons sont simplement montrés dans cet exemple pour illustrer que les requêtes de blocs supplémentaires ne peuvent pas utiliser le jeton de la relation d'Observation. Comme commentaire général sur les jetons, il n'y a aucune autre mention de jetons dans ce document, car les transferts par blocs gèrent les jetons comme tout autre échange CoAP. Comme d'habitude, le client est libre de choisir les jetons pour chaque échange comme il le souhaite.)
Dans l'exemple suivant, le client utilise également la négociation précoce pour limiter la taille de bloc à 64 octets.
CLIENT SERVER
| |
+----->| Header: GET 0x41011636
| GET | Token: 0xfb
| | Uri-Path: status-icon
| | Observe: (empty)
| | Block2: 0/0/64
| |
|<-----+ Header: 2.05 0x61451636
| 2.05 | Token: 0xfb
| | Block2: 0/1/64
| | Observe: 62350
| | ETag: 6f00f38e
| | Max-Age: 60
| | Payload: [64 bytes]
| |
| | (Usual GET transfer left out)
...
| | (Notification of first block)
| |
|<-----+ Header: 2.05 0x4145af9c
| 2.05 | Token: 0xfb
| | Block2: 0/1/64
| | Observe: 62354
| | ETag: 6f00f392
| | Payload: [64 bytes]
| |
+- - ->| Header: 0x6000af9c
| |
| | (Retrieval of remaining blocks)
| |
+----->| Header: GET 0x41011637
| GET | Token: 0xfc
| | Uri-Path: status-icon
| | Block2: 1/0/64
| |
|<-----+ Header: 2.05 0x61451637
| 2.05 | Token: 0xfc
| | Block2: 1/1/64
| | ETag: 6f00f392
| | Payload: [64 bytes]
....
| |
+----->| Header: GET 0x41011638
| GET | Token: 0xfc
| | Uri-Path: status-icon
| | Block2: 4/0/64
| |
|<-----+ Header: 2.05 0x61451638
| 2.05 | Token: 0xfc
| | Block2: 4/0/64
| | ETag: 6f00f392
| | Payload: [53 bytes]
Figure 13 : Séquence Observe avec négociation précoce