一起學習CC3200系列教程之2個TCP_非阻塞及阻塞設置

一起學習CC3200系列教程之2個TCP_非阻塞及阻塞設置

 

阿湯哥

序:

能力有限,難免有錯,有問題請聯繫我,

QQ1519256298       [email protected]

Pdf下載http://pan.baidu.com/s/1hqiWB56

 

關鍵字:socket ,阻塞,非阻塞,SetSockOpt

 

現在我們介紹如果創建一個TCP連接。

開發環境:

CCS,sdk1.1,freertos,

軟件流程:

我們創建兩個任務,第一個任務比第二個任務多了一個網絡設置的功能,其他的一致,我們就用第一個任務來表達,任務初始化CC3200爲STA模式,並連上AP,創建一個socket,讀取遠端的數據,並把讀到的數據原封不動地發送回去。自動檢測socket連接有沒有斷開,並自動重新連接,沒有做網絡斷開連接的檢測。

這裏我們用了兩種方式:阻塞及非阻塞

阻塞:

任務會阻塞在寫和讀的函數上,直到發送出去,讀函數會直接返回,所以在返回值做了一個判斷:有沒有斷開連接,有就重連。當阻塞某一函數時,任務會自動切換。因此不用我們去延遲任務

非阻塞:

任務不會阻塞在讀的函數上,寫函數有沒有阻塞我沒測過,估計得用測量這個函數的執行時間才能知道有沒有阻塞,挺麻煩的,所以略過。當socket斷開連接會導致發送錯誤,利用這個特性,在發送錯誤時我們進行重連,因此這個會導致無用的信息傳輸浪費了電量,而且響應不及時,改進方法:用select,這個改天說。任務不會自動切換,需要我們去延遲任務,切換任務,這裏我是使用的是用SetSockOpt來設置非阻塞的

main函數

//****************************************************************************
//                            MAIN FUNCTION
//****************************************************************************
void main()
{
    long lRetVal = -1;
  
    //Board Initialization
    BoardInit();
    
    //
    // 初始化串口
    //
    PinMuxConfig();
    //UART Initialization
    MAP_PRCMPeripheralReset(PRCM_UARTA0);

    MAP_UARTConfigSetExpClk(CONSOLE,MAP_PRCMPeripheralClockGet(CONSOLE_PERIPH),
                            UART_BAUD_RATE,(UART_CONFIG_WLEN_8 | 
                              UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));

    //Display Application Banner on UART Terminal
    DisplayBanner(APPLICATION_NAME);
    
    //
    // Simplelinkspawntask
    //
    lRetVal = VStartSimpleLinkSpawnTask(SPAWN_TASK_PRIORITY);    
    if(lRetVal < 0)
    {
        UART_PRINT("Unable to start simpelink spawn task\n\r");
        LOOP_FOREVER();
    }


    //創建任務1
    lRetVal = osi_TaskCreate(TcpEchoClient, (signed char*)"TcpEchoClient",
    		TcpEchoClient_STACK_SIZE, NULL, TcpEchoClient_PRIORITY, NULL );
    if(lRetVal < 0)
    {
        UART_PRINT("Unable to create task\n\r");
        LOOP_FOREVER();
    }
    //創建任務2,這個任務必須是比第一個任務的優先級低,因爲第一個任務有一個初始化網絡的設置
    //
    lRetVal = osi_TaskCreate(TcpEchoClient2, (signed char*)"TcpEchoClient2",
    		TcpEchoClient_STACK_SIZE, NULL, TcpEchoClient_PRIORITY - 1, NULL );
    if(lRetVal < 0)
    {
        UART_PRINT("Unable to create task\n\r");
        LOOP_FOREVER();
    }
    //
    // 開始任務調度
    //
    osi_start();

    while (1)
    {

    }

}

任務1,2,網絡設置


//本函數是參考sdk1.1.0的network_if的函數的
static void WlanInit(void) {

    long lRetVal = -1;
    //
    // 復位設備的wlan狀態
    //
    Network_IF_ResetMCUStateMachine();
    //
    // 把設備設置成sta模式
    //
    lRetVal = Network_IF_InitDriver(ROLE_STA);
    if(lRetVal < 0)
    {
       UART_PRINT("Failed to start SimpleLink Device\n\r",lRetVal);
       LOOP_FOREVER();
    }

   //網絡參數
    SecurityParams.Key = (signed char *)SECURITY_KEY;
    SecurityParams.KeyLen = strlen(SECURITY_KEY);
    SecurityParams.Type = SECURITY_TYPE;
    //
    // 連接AP
    //
    lRetVal = Network_IF_ConnectAP(SSID_NAME, SecurityParams);
    if(lRetVal < 0)
    {
       UART_PRINT("Connection to an AP failed\n\r");
       LOOP_FOREVER();
    }
}
void TcpEchoClient(void *pvParameters){
<span style="white-space:pre">	</span>//任務1
    SlSockAddrIn_t  sAddr;
    SlSockNonblocking_t enableOption;
    SlSockKeepalive_t xKeepaliveEnableOption;
    unsigned int ulDestiantionIP;
    char szRevBuf[100];
    int iRevLen,iAddrSize,iStatus;
    int iHeartBeatCounter = 0;

    //設置網絡,
    //爲什麼需要這裏設置?
    //因爲本網絡設置需要啓動任務調度器:這個任務需要調度器去調度VStartSimpleLinkSpawnTask這個任務
    //如果沒有啓動調度器,會導致wlan連不上。
    WlanInit();

    //設置服務器端的ip及端口信息
    sAddr.sin_family = SL_AF_INET;
    sAddr.sin_port = sl_Htons((unsigned short)9000);
    //把“192.168.3.27”轉成一個沒有符號的32整數
    siIp_StrToInt("192.168.3.27",&ulDestiantionIP);
    sAddr.sin_addr.s_addr = sl_Htonl((unsigned int)ulDestiantionIP);

    iAddrSize = sizeof(SlSockAddrIn_t);

    UART_PRINT("\r\nTcpEchoClient1\r\n");
    while(1) {
    	//g_iEchoSocketID 等於0.表示這個socket是沒有連接上的
    	if (g_iEchoSocketID == 0) {
    	    //創建一個socket
    	    g_iEchoSocketID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, 0);
    	    if( g_iEchoSocketID < 0 )
    	    {
    	    		//出錯處理:略
    	    }

    	    // 連接到服務器
    	    iStatus = sl_Connect(g_iEchoSocketID, ( SlSockAddr_t *)&sAddr, iAddrSize);
    	    if( iStatus < 0 )
    	    {
    	        // error
    	        sl_Close(g_iEchoSocketID);
    	        g_iEchoSocketID = 0;
    	    }else {

    	    	UART_PRINT("\r\n1:Echo Socket ID is %d\r\n",g_iEchoSocketID);
    	    }
#if TCP_IS_NOBOLCK	//設置成非阻塞形式,經檢測,遠端斷開連接時不會發生中斷,通知遠端斷開連接
    	    enableOption.NonblockingEnabled = 1;
    	    sl_SetSockOpt(g_iEchoSocketID,SL_SOL_SOCKET,SL_SO_NONBLOCKING, (_u8 *)&enableOption,sizeof(enableOption)); // Enable/disable nonblocking mode
#endif
    	    MAP_UtilsDelay(8000000);

    	}
#if TCP_IS_NOBOLCK
    	//當設置成非阻塞的時候,遠端斷開並不會導致中斷髮生,爲了檢測遠端有沒有斷開這個連接
    	//需要我們去主動的發送,如果發送不成功就是斷開連接了
    	iHeartBeatCounter++;
    	if ((iHeartBeatCounter % 5) == 0){
    		iStatus = sl_Send(g_iEchoSocketID, "1:這是一個心跳機制的信息", sizeof("這是一個心跳機制的信息"), 0 );
    		if( iStatus < 0 ){

    			UART_PRINT("\r\n1:發送失敗 \r\n");
    			sl_Close(g_iEchoSocketID);
    			g_iEchoSocketID = 0;
    		}


    	}
#endif
    	//接收數據,這個接收可能是阻塞的也可能是非阻塞的,取決你的設置
    	iRevLen = sl_Recv(g_iEchoSocketID,szRevBuf,100,0);
    	if (iRevLen > 0) {
			iStatus = sl_Send(g_iEchoSocketID, szRevBuf, iRevLen, 0 );
			if( iStatus < 0 )
			{
				UART_PRINT("\r\n1:發送失敗 \r\n");
				sl_Close(g_iEchoSocketID);
				g_iEchoSocketID = 0;

			}
    	} else {
    		UART_PRINT("\r\n1:%d   沒有收到數據  %d \r\n",g_iEchoSocketID,iRevLen);
#if TCP_IS_NOBOLCK == 0
    		UART_PRINT("\r\nsocket 1 斷開連接了\r\n");
    		g_iEchoSocketID = 0;

#endif
    	}

#if TCP_IS_NOBOLCK
    	//當是非阻塞的時候,需要主動讓任務睡眠,切換任務
    	osi_Sleep(1000);

#endif
    }
}
void TcpEchoClient2(void *pvParameters){

    SlSockAddrIn_t  sAddr;
    SlSockNonblocking_t enableOption;
    SlSockKeepalive_t xKeepaliveEnableOption;
    unsigned int ulDestiantionIP;
    char szRevBuf[100];
    int iRevLen,iAddrSize,iStatus;
    int iHeartBeatCounter = 0;




    //filling the TCP server socket address
    sAddr.sin_family = SL_AF_INET;
    sAddr.sin_port = sl_Htons((unsigned short)9000);
    siIp_StrToInt("192.168.3.27",&ulDestiantionIP);
    sAddr.sin_addr.s_addr = sl_Htonl((unsigned int)ulDestiantionIP);

    iAddrSize = sizeof(SlSockAddrIn_t);

    UART_PRINT("\r\nTcpEchoClient2\r\n");
    while(1) {
    	osi_Sleep(2000);
    	if (g_iEchoSocketID2 == 0) {
    	    // creating a TCP socket
    		g_iEchoSocketID2 = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, 0);
    	    if( g_iEchoSocketID2 < 0 )
    	    {

    	    }

    	    // connecting to TCP server
    	    iStatus = sl_Connect(g_iEchoSocketID2, ( SlSockAddr_t *)&sAddr, iAddrSize);
    	    if( iStatus < 0 )
    	    {
    	        // error
    	        sl_Close(g_iEchoSocketID2);
    	    }else {

    	    	UART_PRINT("\r\n2:Echo Socket ID is %d\r\n",g_iEchoSocketID2);
    	    }
#if TCP_IS_NOBOLCK		//設置成非阻塞形式,經檢測,遠端斷開連接時不會發生中斷,通知遠端斷開連接
    	    enableOption.NonblockingEnabled = 1;
    	    sl_SetSockOpt(g_iEchoSocketID2,SL_SOL_SOCKET,SL_SO_NONBLOCKING, (_u8 *)&enableOption,sizeof(enableOption)); 
#endif
    	    MAP_UtilsDelay(8000000);

    	}
#if TCP_IS_NOBOLCK
    	iHeartBeatCounter++;
    	if ((iHeartBeatCounter % 5) == 0){
    		iStatus = sl_Send(g_iEchoSocketID2, "2:這是一個心跳機制的信息", sizeof("這是一個心跳機制的信息"), 0 );
    		if( iStatus < 0 ){
    			UART_PRINT("\r\n2:發送失敗 \r\n");
    			sl_Close(g_iEchoSocketID2);
    			g_iEchoSocketID2 = 0;
    		}


    	}
#endif

    	iRevLen = sl_Recv(g_iEchoSocketID2,szRevBuf,100,0);
    	if (iRevLen > 0) {
			iStatus = sl_Send(g_iEchoSocketID2, szRevBuf, iRevLen, 0 );
			if( iStatus < 0 )
			{
				// error、
				UART_PRINT("\r\n2:發送失敗 \r\n");
				sl_Close(g_iEchoSocketID2);
				g_iEchoSocketID2 = 0;

			}
    	} else {

    		UART_PRINT("\r\n2:%d   沒有收到數據  %d \r\n",g_iEchoSocketID,iRevLen);
#if TCP_IS_NOBOLCK == 0
    		UART_PRINT("\r\nsocket 2 斷開連接了\r\n");
    		g_iEchoSocketID2 = 0;

#endif
    	}
#if TCP_IS_NOBOLCK
    	osi_Sleep(1000);

#endif

    }
}

宏定義

#define TcpEchoClient_STACK_SIZE          2048
#define TcpEchoClient_PRIORITY       3

#define TCP_IS_NOBOLCK  1
/* AP Security Parameters */
SlSecParams_t SecurityParams = {0};
int g_iEchoSocketID = 0;
int g_iEchoSocketID2 = 0;


其他函數

/**
 * @brief 把字符性的ip轉成整形的ip
 * 譬如“192.179.1.1” -->0xc0a0101
 * 返回 0 成功
 * - 1 失敗,
 * 請注意這個函數最好是輸入符合“192.179.1.1”這樣形式的
 */
signed int siIp_StrToInt(char *cpIp,unsigned int *uipIp) {
    unsigned int retIp,temp;
    unsigned char i,str[20],*p,*a[5]={0};
    i  = 0 ;
    p = str;
    strncpy(p,cpIp,16);
    retIp = 0;
    while((a[i]  = strtok(p,".")) != NULL) {
        p = NULL;
        temp = strtoul(a[i],0,10);
        retIp <<= 8;
        retIp |= temp;
        i++;
    }

    if (i == 4) {
        *uipIp = retIp;
        return 0;
    } else {
        return -1;
    }
}



發佈了44 篇原創文章 · 獲贊 13 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章