天天看點

Mosquitto之Durable Connection逾時斷開與删除

本文章将進入mosquitto源碼,介紹幾個與用戶端相關的時間變量,初探這些變量的含義。由于能力有限,如有錯誤,歡迎批評指正。注意:以下主要針對Durable Connection而言。

  • keepalive:對應于mosquitto.conf中的max_keepalive配置選項,表示broker與client(橋模式的client除外)之間互動時,封包的最大有效時間,這個時間也可以成為保活時間,目前在mosquitto的實作中,保活時間被放大到1.5倍。用戶端逾時後,連接配接将會斷開。
  • persistent_client_expiration:Durable Connection逾時時間。
  • session_expiry_interval:連接配接會話間隔時間。存在兩個特殊值:0表示立即删除會話,UINT32_MAX表示永不删除會話。在MQTT V5版本以前,本值預設為UINT32_MAX。

以上幾個變量之間的關系如下:

1、keepalive大于0,如果是,則如果用戶端在1.5倍的時間内未發送封包,那麼broker将主動斷開與該用戶端的連接配接。keepalive等于0時表示永遠存活。橋模式下的用戶端不受本參數影響,即:永不逾時。

if(!(context->keepalive)
	|| context->bridge
	|| now - context->last_msg_in <= (time_t)(context->keepalive)*3/2){
    ....
} else {
    /* Client has exceeded keepalive*1.5 */
    do_disconnect(db, context, MOSQ_ERR_KEEPALIVE);
}
           

2、連接配接斷開之後,mosquitto将檢查連接配接會話的間隔時間(session_expiry_interval)。如果該變量等于0,那麼直接删除該clientid。如果該變量等于UINT32_MAX,則該clientid表示的會話資訊将永久儲存。如果大于0,且不等于UINT32_MAX,進入下個步驟。

if(context->sock == INVALID_SOCKET 
   && context->session_expiry_interval > 0
   && context->session_expiry_interval != UINT32_MAX)
{
    /* This is a persistent client, check to see if the
	 * last time it connected was longer than
	 * persistent_client_expiration seconds ago. If so,
	 * expire it and clean up.
	 */
	if(now > context->session_expiry_time) {
		...
		G_CLIENTS_EXPIRED_INC();
		context->session_expiry_interval = 0;
		mosquitto__set_state(context, mosq_cs_expiring);
		do_disconnect(db, context, MOSQ_ERR_SUCCESS);
	}
}
           

3、如果persistent_client_expiration大于0,mosquitto根據的persistent_client_expiration值與session_expiry_interval進行比較,選擇其中最小的值作為該會話的逾時時間;如果persistent_client_expiration值未配置,那麼将使用session_expiry_interval的值作為逾時時間,并把該會話的資訊添加到過期清單中。

item->context->session_expiry_time = time(NULL);
if(db->config->persistent_client_expiration == 0
  || db->config->persistent_client_expiration < item->context->session_expiry_interval)
{
    item->context->session_expiry_time += item->context->session_expiry_interval;
} else {
    item->context->session_expiry_time += db->config->persistent_client_expiration;
}
context->expiry_list_item = item;

DL_INSERT_INORDER(expiry_list, item, session_expiry__cmp);
...
           

4、該用戶端未在逾時時間内進行重連,broker會将用戶端的會話資訊删除回收。由于broker中該會話資訊已經被删除,是以假設用戶端斷開之後,broker在該topic上接收到了很多消息,那麼這些消息以後也将不會再發送給該用戶端。對于永久存活的用戶端,Qos大于0的消息在後續用戶端重連的時候,這些用戶端仍然能夠接收到那些消息。