怎樣解決W5200/W5500在TCP通訊過程中意外斷開?(Keepalive)

WIZnet發表於2015-05-06

在使用W5200W5500TCP通訊過程中,有一個非常容易被問到的問題:

(這裡以W5200為例)

W5200作為伺服器,假如客戶端的網線斷開  瞬間停電,伺服器該怎樣判斷?

那麼當客戶端由於這些原因忽然斷開,該怎樣解決?

今天給大家介紹解決以上問題的辦法,即如何使用Keepalive

 

什麼是Keepalive

 

Keepalive即心跳檢測,以下簡稱KA,之所以稱之為心跳檢測是因為它像心跳一樣每隔一段時間發一次,以此來告訴對方自己是否存活。心跳檢測用於TCP通訊過程中伺服器檢測客戶端是處於長時間空閒(線上)還是已經斷開,一般採用客戶端定時傳送簡單的通訊包,一般是很小的包或者空包給伺服器(W5200的心跳包為1位元組),如果在指定時間內沒有收到該心跳包,則伺服器會判斷客戶端已經斷開,此時程式中的Socket狀態機會轉到SOCKET_CLOSED並重新開啟Socket去連線伺服器/監聽客戶端。

 

KeepAlive怎麼分類?

 

       KA根據發出方不同可以分為兩種,一種是由客戶端發給伺服器的心跳包,一種是伺服器發給客戶端的心跳包,選擇哪一種方式需要看哪一方實現起來方便合理。需要注意的是,W5200根據合理的設計,其心跳包需要在Socket TCP連線建立之後,伺服器和客戶端至少進行一次資料互動,且在設定的時間內沒有資料互動時發出。

 

W5200 KA程式說明

       下面我以W5200TCP Server官方例程為例,用PC建立TCP客戶端來連線W5200,說明KA的實現方法。

 

定義和初始化部分:

程式中用到了定時器和中斷函式,在w5200_config.c中做了定義: 
 

 void Timer_Configuration(void)

{

  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  TIM_TimeBaseStructure.TIM_Period = 1000;         

  TIM_TimeBaseStructure.TIM_Prescaler = 0;     

  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;   

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 

  TIM_PrescalerConfig(TIM2, 71, TIM_PSCReloadMode_Immediate); 

  TIM_Cmd(TIM2, ENABLE);

  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

void Timer2_ISR(void)

{

  ms++;                                                                 // 等待時間自增,單位為ms

  if((ms % 1000)==0)                                             // 當等待時間增加到某一秒

  {

    if(ka_tick_flag==1)ka_no_data_tick++;                 // KA定時器標誌位為1,無資料傳輸時間計時器自增

    if(ka_no_data_tick>=NO_DATA_PERIOD)            

    {

   ka_send_tick++;                              // 當無資料傳輸時間計時器值大於NO_DATA_PERIODKA傳送定時器開始自增

    if(ka_send_tick>=KA_SEND_PERIOD)

      {

        ka_sen       d_flag=1;                           // KA傳送定時器的大於KA_SEND_PERIODKA傳送標誌位置1,傳送一個KA

      }

    }   

    printf(".");                           // 當時間沒到整秒,發一個“.

  }

}

 

在主程式中進行初始化:

Timer_Configuration();                      // 定時器初始化

NVIC_Configuration();                        // 中斷函式初始化 

 

程式中定義了ka_tick_flagKA定時器開始計時標誌位)、ka_send_flagKA傳送標誌位)、ka_no_data_tickKA無資料傳輸時間計時器)以及ka_send_tickKA傳送定時器)。在w5200_config.c中對以上定義進行了初始化:

 

uint32 ka_no_data_tick=0;                                  // 定義無資料傳輸時間計時器

uint8 ka_tick_flag=0;                                          // 定義KA定時器開始計時標誌位

uint32 ka_send_tick=0;                                       // 定義KA傳送定時器

uint8 ka_send_flag=0;                                         // 定義KA傳送標誌位

 

主迴圈部分:

 

當程式燒錄後,按Reset鍵重啟W5200後伺服器開啟一個Socket,此時SocketSOCK_CLOSED變為SOCK_INIT並處於監聽狀態。PC建立客戶端成功連線W5200後,Socket處於SOCK_ESTABLISHED,下面是程式具體的操作過程:

 

case SOCK_ESTABLISHED:                                                      // Socket處於連線建立狀態

if(getSn_IR(0)& Sn_IR_CON)

         {

           setSn_IR(0, Sn_IR_CON);                                            // Sn_IR的第0位置1

           ka_tick_flag=0;                                                          // KA定時器開始計時標誌位清零

           ka_no_data_tick=0;                                                    // 無資料傳輸時間計時器

           ka_send_flag=0;                                                        // KA傳送標誌位清零

           ka_send_tick=0;                                                        // KA傳送定時器清零

         }

         if ((len = getSn_RX_RSR(0)) > 0)                

         {                                   

           len = recv(0, RX_BUF, len);                                          // W5200收到資料並儲存到len

           send(0,RX_BUF,len,(bool)0);                             // W5200將收到的資料發回客戶端

           if(ka_tick_flag==0)                            

           {

                  ka_tick_flag=1;                                             // W5200同客戶端進行了一次通訊後,將KA定時器開始計時標誌位置1,進入定時器中斷函式,只要接下來在NO_DATA_PERIOD內沒有資料通訊,就開始發KA

            }

             ka_no_data_tick=0;                                                    // 無資料傳輸時間計時器清零

             ka_send_tick=0;                                                           // KA傳送定時器清零

           }

         // KA傳送過程

if(ka_send_flag)

         {

           ka_send_flag=0;                                                            // KA傳送標誌位清零

           ka_send_tick=0;                                                            // KA傳送定時器清零

           send_keepalive(0);                                                         // W5200KA包給客戶端

           printf("*");                                                                    // KA”*”為標誌在串列埠列印出來

         }

break;

 

例程下載:

W5200: http://pan.baidu.com/s/1eQ3vkZo

W5500: http://pan.baidu.com/s/1sj7ILBn

感謝閱讀! 
 

歡迎訪問:

WIZnet官方網站:http://www.iwiznet.co.kr 

WIZnet官方微博:http://weibo.com/wiznet2012

WIZnet微信公眾平臺:

相關文章