【STM32F407】第9章 ThreadX NetXDUO之TCP客戶端
最新教程下載:http://www.armbbs.cn/forum.php?mod=viewthread&tid=104619
第9章 ThreadX NetXDUO之TCP客戶端
本章節為大家講解NetXDUO的TCP客戶端實現,學習本章節前,務必要優先學習第7章TCP傳輸控制協議基礎知識。有了這些基礎知識之後,再搞本章節會有事半功倍的效果。
9.1 初學者重要提示
9.2 TCP客戶端API函式
9.3 TCP客戶端的實現方法
9.4 網路除錯助手和板子的除錯操作步驟
9.5 實驗例程說明
9.6 總結
9.1 初學者重要提示
1、學習本章節前,務必保證已經學習了第7章的基礎知識。
2、本章要掌握的函式稍多,可以先學會基本的使用,然後再深入瞭解這些函式使用時的注意事項,爭取達到熟練使用。
3、socket和監聽的關係:
- 建立的一個socket只能建立一個監聽。
- 建立的一個socket不能夠監聽多個 。
- 建立多個socket可以建立多個監聽。
- 建立多個socket可以僅建立一個監聽。
4、ThreadX NetXDUO的TCP Socket資料包申請和釋放問題
- 函式nx_tcp_socket_receive 會申請一個NX_PACKET資料包用於接收,如果使用者不使用了必須使用函式nx_packet_release釋放。
- 使用函式nx_tcp_socket_send必須有申請好的NX_PACKET資料包,可以使用函式nx_packet_allocate申請,也可以使用nx_tcp_socket_receive申請的。
特別要注意的地方來了,函式nx_tcp_socket_send呼叫後會釋放nx_packet_allocate或者nx_tcp_socket_receive申請的資料包。無需使用者再去呼叫函式nx_packet_release釋放。
9.2 TCP客戶端API函式
下面一張圖說明ThreadX NetXDUO TCP Socket的各種API玩法:
9.2.1 函式nx_system_initialize
函式原型:
VOID nx_system_initialize(VOID);
函式描述:
NetXDUO初始化,所有其它功能呼叫之前必須優先呼叫此函式。
9.2.2 函式nx_packet_pool_create
函式原型:
UINT nx_packet_pool_create( NX_PACKET_POOL *pool_ptr, CHAR *name, ULONG payload_size, VOID *memory_ptr, ULONG memory_size);
函式描述:
此函式用於資料包記憶體池建立
函式引數:
- 第1個引數是記憶體池控制塊的地址。
- 第2個引數是記憶體池名字。
- 第3個引數是記憶體池中每個資料包的位元組數。 此值必須至少為 40 個位元組,並且還必須可以被 4 整除。
- 第4個引數是記憶體池中資料地址,此地址必須ULONG對齊。
- 第5個引數是記憶體池大小。
- 返回值:
- NX_SUCCESS:(0x00) 建立記憶體池成功。
- NX_PTR_ERROR:(0x07) 第1個引數地址無效。
- NX_SIZE_ERROR:(0x09) 第5個引數記憶體池大小無效。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
使用舉例:
/* 建立記憶體池 */ status = nx_packet_pool_create(&pool_0, /* 記憶體池控制塊 */ "NetX Main Packet Pool",/* 記憶體池名 */ 1536, /* 記憶體池每個資料包大小,單位位元組此值必須至少為 40 個位元組,並且還必須可以被 4 整除 */ (ULONG*)(((int)packet_pool_area + 15) & ~15) ,/* 記憶體池地址,此地址必須ULONG對齊 */ NX_PACKET_POOL_SIZE); /* 記憶體池大小 */
9.2.3 函式nx_ip_create
函式原型:
UINT nx_ip_create( NX_IP *ip_ptr, CHAR *name, ULONG ip_address, ULONG network_mask, NX_PACKET_POOL *default_pool, VOID (*ip_network_driver)(NX_IP_DRIVER *), VOID *memory_ptr, ULONG memory_size, UINT priority);
函式描述:
此函式使用使用者提供的 IP 地址,資料包記憶體記憶體池和網路驅動程式建立 IP 例項。注意,直到 IP任務執行之後,才會呼叫網路驅動。
函式引數:
- 第1個引數是建立IP例項的控制塊指標。
- 第2個引數是IP例項的名字。
- 第3個引數是IP地址。
- 第4個引數是子網掩碼
- 第5個引數是記憶體池地址。
- 第6個引數是網絡卡驅動地址。
- 第7個引數是IP任務棧地址
- 第8個引數是IP任務棧大小,單位位元組。
- 第9個引數是IP任務優先順序。
- 返回值
- NX_SUCCESS:(0x00) 建立 IP 例項成功。
- NX_NOT_IMPLEMENTED:(0x4A) 未正確配置 NetX Duo 庫。
- NX_PTR_ERROR:(0x07) IP控制塊地址、網路驅動函式指標、記憶體池地址或任務棧地址無效。
- NX_SIZE_ERROR:(0x09) 提供的任務棧大小太小。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
- NX_IP_ADDRESS_ERROR:(0x21) 提供的 IP 地址無效。
- NX_OPTION_ERROR:(0x21) 提供的 IP 任務優先順序無效。
使用舉例:
/* 例化IP */ status = nx_ip_create(&ip_0, /* IP例項控制塊 */ "NetX IP Instance 0", /* IP例項名 */ IP_ADDRESS(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3), /* IP地址 */ 0xFFFFFF00UL, /* 子網掩碼 */ &pool_0, /* 記憶體池 */ nx_driver_stm32h7xx, /* 網絡卡驅動 */ (UCHAR*)AppTaskNetXStk, /* IP任務棧地址 */ sizeof(AppTaskNetXStk), /* IP任務棧大小,單位位元組 */ APP_CFG_TASK_NETX_PRIO); /* IP任務優先順序 */
9.2.4 函式nx_arp_enable
函式原型:
UINT nx_arp_enable( NX_IP *ip_ptr, VOID *arp_cache_memory, ULONG arp_cache_size);
函式描述:
此函式用於使能ARP地址解析。
函式引數:
- ip_ptr:IP例項地址。
- arp_cache_memory:ARP快取地址。
- arp_cache_size:每個 ARP 條目均為 52 個位元組,因此,ARP 條目總數是52位元組整數倍。
- 返回值
- NX_SUCCESS:(0x00) 啟用 ARP 成功。
- NX_PTR_ERROR:(0x07) IP例項地址或ARP快取地址無效。
- NX_SIZE_ERROR:(0x09) 使用者提供的 ARP 快取記憶體太小。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
- NX_ALREADY_ENABLED:(0x15) 此元件已啟用。
使用舉例:
int32_t tcp_sock; tcp_sock = netTCP_GetSocket (tcp_cb_server); if (tcp_sock > 0) { res = netTCP_Listen (tcp_sock, PORT_NUM); } if(netTCP_SendReady(tcp_sock) == true ) { }
9.2.5 函式nx_ip_fragment_enable
函式原型:
UINT nx_ip_fragment_enable(NX_IP *ip_ptr);
函式描述:
此函式用於啟用 IPv4 和 IPv6 資料包分段和重組功能。建立 IP 任務時,此服務會自動禁用。
函式引數:
1、第1個引數是IP例項地址。
2、返回值
- NX_SUCCESS:(0x00) 啟用 IP 分段成功。
- NX_PTR_ERROR:(0x07) IP 例項地址無效。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
- NX_NOT_ENABLED:(0x14) IP 分段功能未編譯到 NetX Duo 中。
使用舉例:
/* 使能fragment */ status = nx_ip_fragment_enable(&ip_0);
9.2.6 函式nx_tcp_enable
函式原型:
UINT nx_tcp_enable(NX_IP *ip_ptr);
函式描述:
此函式用於使能TCP元件。
函式引數:
1、第1個引數是IP例項地址。
2、返回值
- NX_SUCCESS:(0x00) 啟用 TCP 成功。
- NX_ALREADY_ENABLED:(0x15) TCP 已啟用。
- NX_PTR_ERROR:(0x07) IP 例項地址無效。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
使用舉例:
/* 使能TCP */ status = nx_tcp_enable(&ip_0);
9.2.7 函式nx_tcp_client_socket_bind
函式原型:
UINT nx_tcp_client_socket_bind( NX_TCP_SOCKET *socket_ptr, UINT port, ULONG wait_option);
函式描述:
此函式用於為建立的TCP Socket繫結埠。如果設定的埠號還不可用,可以設定等待時間。
函式引數:
1、第1個引數是TCP Socket指標。
2、第2個引數是繫結的埠,範圍1 -65535。如果設定為NX_ANY_PORT(0x0000),則會搜尋一個可用埠號。
3、第3個引數是埠號不可用時,等待時間定義:
- NX_NO_WAIT (0x00000000)
- NX_WAIT_FOREVER (0xFFFFFFFF)
- 等待時間:(0x00000001 到 0xFFFFFFFE),單位是ThreadX系統時鐘節拍。
4、返回值
- NX_SUCCESS:(0x00) 繫結TCP Socket成功。
- NX_ALREADY_BOUND:(0x22) 此TCP Socket已與另一 TCP 埠繫結。
- NX_PORT_UNAVAILABLE:(0x23) 埠已與其他Socket繫結。
- NX_NO_FREE_PORTS:(0x45) 沒有可用的埠。
- NX_WAIT_ABORTED:(0x1A) 已通過呼叫 tx_thread_wait_abort 中止請求。
- NX_INVALID_PORT:(0x46) 埠無效。
- NX_PTR_ERROR:(0x07) Socket指標無效。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
- NX_NOT_ENABLED:(0x14) 此元件尚未啟用。
使用舉例:
/* 繫結埠 */ ret = nx_tcp_client_socket_bind(&TCPSocket, DEFAULT_PORT, NX_WAIT_FOREVER); if (ret != NX_SUCCESS) { Error_Handler(__FILE__, __LINE__); }
9.2.8 函式nx_tcp_client_socket_unbind
函式原型:
UINT nx_tcp_client_socket_unbind(NX_TCP_SOCKET *socket_ptr);
函式描述:
此函式用於解除TCP Socket繫結的埠。
函式引數:
1、 第1個引數是TCP Socket指標。
2、 返回值
- NX_SUCCESS:(0x00) 取消繫結Socket成功。
- NX_NOT_BOUND:(0x24) Socket未與任何埠繫結。
- NX_NOT_CLOSED:(0x35) Socket尚未斷開連線。
- NX_PTR_ERROR:(0x07) Socket指標無效。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
- NX_NOT_ENABLED (0x14) 尚未啟用此元件。
使用舉例:
/* 繫結埠 */ ret = nx_tcp_client_socket_bind(&TCPSocket, DEFAULT_PORT, NX_WAIT_FOREVER); if (ret != NX_SUCCESS) { Error_Handler(__FILE__, __LINE__); }
9.2.9 函式nx_tcp_client_socket_connect
函式原型:
UINT nx_tcp_client_socket_connect( NX_TCP_SOCKET *socket_ptr, ULONG server_ip, UINT server_port, ULONG wait_option);
函式描述:
此函式用於建立TCP客戶端連線遠端伺服器。
函式引數:
1、 第1個引數是TCP Socket指標。
2、 第2個引數是遠端伺服器IP。
3、 第3個引數是遠端埠。
4、 第4個引數連線遠端伺服器的等待選項,支援的引數如下:
- NX_NO_WAIT (0x00000000)
- NX_WAIT_FOREVER (0xFFFFFFFF)
- 等待時間:(0x00000001 到 0xFFFFFFFE),單位是ThreadX系統時鐘節拍。
5、 返回值:
- NX_SUCCESS:(0x00) 連線套接字成功。
- NX_NOT_BOUND:(0x24) 套接字未繫結。
- NX_NOT_CLOSED:(0x35) 套接字未處於關閉狀態。
- NX_IN_PROGRESS (0x37) 未指定等待,正在嘗試連線。
- NX_INVALID_INTERFACE:(0x4C) 提供了無效的介面。
- NX_WAIT_ABORTED:(0x1A) 已通過呼叫 tx_thread_wait_abort 中止所請求的掛起。
- NX_IP_ADDRESS_ERROR:(0x21) 伺服器 IP 地址無效。
- NX_INVALID_PORT (0x46) 埠無效。
- NX_PTR_ERROR:(0x07) 套接字指標無效。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
- NX_NOT_ENABLED (0x14) 尚未啟用此元件。
使用舉例:
/* 連線遠端伺服器 */ ret = nx_tcp_client_socket_connect(&TCPSocket, TCP_SERVER_ADDRESS, TCP_SERVER_PORT, NX_WAIT_FOREVER); if (ret != NX_SUCCESS) { Error_Handler(__FILE__, __LINE__); }
9.2.10 函式nx_tcp_socket_info_get
函式原型:
UINT nx_tcp_socket_info_get( NX_TCP_SOCKET *socket_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, ULONG *tcp_packets_received, ULONG *tcp_bytes_received, ULONG *tcp_retransmit_packets, ULONG *tcp_packets_queued, ULONG *tcp_checksum_errors, ULONG *tcp_socket_state, ULONG *tcp_transmit_queue_depth, ULONG *tcp_transmit_window, ULONG *tcp_receive_window);
函式描述:
用於獲取TCP Socket相關資訊。
函式引數:
- 第1個引數是TCP Socket指標。
- 第2個引數是傳送的TCP資料包總數目。
- 第3個引數是傳送的TCP總位元組數。
- 第4個引數是接收的TCP資料包總數目。
- 第5個引數是接收的TCP總位元組數。
- 第6個引數是重新傳輸的TCP資料包總數目。
- 第7個引數是Socket上TCP排隊的TCP資料包總數。
- 第8個引數是Socket上有校驗和錯誤的TCP資料包總數。
- 第9個引數是Socket當前狀態。
- 第10個引數是仍在排隊等待ACK的傳送資料包總數。
- 第11個引數是當前傳送視窗大小。
- 第12個引數是當前接收視窗大小。
- 返回值:
- NX_SUCCESS:(0x00) 檢索 TCP Socket資訊成功。
- NX_PTR_ERROR:(0x07) Socket指標無效。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
- NX_NOT_ENABLED:(0x14) 此元件尚未啟用。
使用舉例:
/* 獲取socket狀態 */ nx_tcp_socket_info_get(&TCPSocket, /* TCP Socket控制塊 */ NULL, /* 傳送的TCP資料包總數目 */ NULL, /* 傳送的TCP總位元組數 */ NULL, /* 接收TCP資料包總數目 */ NULL, /* 接收的TCP總位元組數 */ NULL, /* 重新傳輸的TCP資料包總數目 */ NULL, /* Socket上TCP排隊的TCP資料包總數 */ NULL, /* Socket上有校驗和錯誤的TCP資料包總數 */ &socket_state, /* Socket當前狀態 */ NULL, /* 仍在排隊等待ACK的傳送資料包總數 */ NULL, /* 當前傳送視窗大小 */ NULL); /* 當前接收視窗大小 */
9.2.11 函式nx_tcp_socket_receive
函式原型:
UINT nx_tcp_socket_receive( NX_TCP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, ULONG wait_option);
函式描述:
此函式用於從指定的Socket接收TCP資料,如果指定的Socket上沒有已經排隊的資料,則呼叫方會根據提供的等待選項引數掛起。
函式引數:
1、 第1個引數是TCP Socket指標
2、 第2個引數是TCP資料包指標。
3、 第3個引數是Socket佇列上沒有資料時的處理:
- NX_NO_WAIT (0x00000000)。
- NX_WAIT_FOREVER (0xFFFFFFFF)。
- 以時鐘週期為單位的超時值(0x00000001 到 0xFFFFFFFE)。
4、 返回值:
- NX_SUCCESS:(0x00) 接收Socket資料成功。
- NX_NOT_BOUND:(0x24) Socket未繫結。
- NX_NO_PACKET:(0x01) 未收到任何資料。
- NX_WAIT_ABORTED:(0x1A) 通過呼叫 tx_thread_wait_abort 中止掛起。
- NX_NOT_CONNECTED:(0x38) 該Socket不再處於已連線狀態。
- NX_PTR_ERROR:(0x07) Socket指標或返回資料包指標無效。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
- NX_NOT_ENABLED:(0x14) 此元件尚未啟用。
注意事項:
- 如果返回了 NX_SUCCESS,則應用程式負責:不再需要收到資料包時將其釋放。
使用舉例:
/* 接收TCP客戶端發的TCP資料包 */ ret = nx_tcp_socket_receive(&TCPSocket, /* TCP Socket控制塊 */ &data_packet, /* 接收到的資料包 */ NX_WAIT_FOREVER); /* 永久等待 */
9.2.12 函式nx_tcp_socket_send
函式原型:
UINT nx_tcp_socket_send( NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, ULONG wait_option);
函式描述:
此函式用於TCP Socket資料傳送。 如果接收方最近一次建議的視窗大小低於此請求,則此函式可以根據指定的等待引數掛起。此函式可保證不會將大於 MSS 的資料包資料傳送到 IP 層。
函式引數:
1、 第1個引數是TCP Socket控制代碼。
2、 第2個引數是TCP資料包指標。
3、 第3個引數是傳送的資料包大於接收方視窗大小時的引數處理,支援如下引數:
- NX_NO_WAIT (0x00000000)
- NX_WAIT_FOREVER (0xFFFFFFFF)
- 以時鐘週期為單位的超時值(0x00000001 到 0xFFFFFFFE)
4、 返回值,返回以下幾種狀態值:
- NX_SUCCESS:(0x00) Socket傳送成功。
- NX_NOT_BOUND:(0x24) Socket未與任何埠繫結。
- NX_NO_INTERFACE_ADDRESS:(0x50) 找不到合適的傳出介面。
- NX_NOT_CONNECTED:(0x38) 套接字不再處於已連線狀態。
- NX_WINDOW_OVERFLOW:(0x39) 請求大於接收方所播發的視窗大小(以位元組為單位)。
- NX_WAIT_ABORTED:(0x1A) 已通過呼叫 tx_thread_wait_abort 中止所請求的掛起。
- NX_INVALID_PACKET:(0x12) 資料包未分配。
- NX_TX_QUEUE_DEPTH:(0x49) 已達到最大傳輸佇列深度。
- NX_OVERFLOW:(0x03) 資料包追加指標無效。
- NX_PTR_ERROR:(0x07) 套接字指標無效。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
- NX_NOT_ENABLED:(0x14) 此元件尚未啟用。
- NX_UNDERFLOW:(0x02) 資料包前置指標無效。
注意事項:
- 除非返回了錯誤,否則應用程式不應在呼叫此函式後釋放該資料包。這樣做會導致不可預知的結果,因為網路驅動程式還會在傳輸後嘗試釋放該資料包。
使用舉例:
/* 立即將接收到的資料傳送回去 */ ret = nx_tcp_socket_send(&TCPSocket, /* TCP Socket控制塊 */ data_packet, /* 資料包 */ NX_WAIT_FOREVER); /* 永久等待 */
9.2.13 函式nx_packet_data_retrieve
函式原型:
UINT nx_packet_data_retrieve( NX_PACKET *packet_ptr, VOID *buffer_start, ULONG *bytes_copied);
函式描述:
此函式用於將提供的資料包中的資料複製到提供的緩衝區。複製的實際位元組數由形參bytes_copied 所指向的儲存單元返回。
注意,此函式不會更改該資料包的內部狀態。檢索的資料仍存在於該資料包中。
函式引數:
1、 第1個引數是指向源資料包的指標
2、 第2個引數是目的資料包的地址。
3、 第3個引數是最終複製的位元組數儲存地址。
4、 返回值,返回以下幾種狀態值:
- NX_SUCCESS:(0x00)複製資料包資料成功。
- NX_INVALID_PACKET:(0x12) 資料包無效。
- NX_PTR_ERROR:(0x07) 形參地址無效。
注意事項:
目標緩衝區的大小必須足以容納該資料包的內容。否則記憶體會損壞,導致不可預知的結果。
使用舉例:
/* 獲取客戶端發來的資料 */ nx_packet_data_retrieve(data_packet, /* 接收到的資料包 */ data_buffer, /* 解析出資料 */ &bytes_read); /* 資料大小 */
9.2.14 函式nx_packet_release
函式原型:
UINT nx_packet_release(NX_PACKET *packet_ptr);
函式描述:
此函式用於釋放資料包,包括連結到指定資料包的任何其他資料包。如果有其他任務在等待這個資料包,則該任務會獲得該資料包並繼續執行。
函式引數:
1、 第1個引數是資料包地址。
2、 返回值,返回以下幾種狀態值:
- NX_SUCCESS:(0x00) 釋放資料包成功。
- NX_PTR_ERROR:(0x07) 資料包指標無效。
- NX_UNDERFLOW:(0x02) 預置指標小於有效負載開始位置。
- NX_OVERFLOW:(0x03) 追加指標大於有效負載結束位置。
注意事項:
應用程式必須防止多次釋放同一資料包,否則會導致不可預知的結果。
9.2.15 函式nx_tcp_socket_disconnect
函式原型:
UINT nx_tcp_socket_disconnect( NX_TCP_SOCKET *socket_ptr, ULONG wait_option);
函式描述:
此函式用於斷開已建立的客戶端或伺服器Socket。在伺服器Socket斷開連線後應該有一個取消接受請求,而斷開連線的客戶端Socket會處於準備好接受其他連線請求的狀態。 如果斷開連線過程無法立即完成,則該函式會根據提供的等待選項掛起。
函式引數:
1、 第1個引數是TCP Socket地址。
2、 第2個引數等待斷開連線時,支援的引數:
- NX_NO_WAIT (0x00000000)。
- NX_WAIT_FOREVER (0xFFFFFFFF)。
- 以時鐘週期為單位的超時值(0x00000001 到 0xFFFFFFFE)。
3、 返回值,返回以下幾種狀態值:
- NX_SUCCESS:(0x00) 斷開Socket連線成功。
- NX_NOT_CONNECTED:(0x38) 指定的Socket未連線。
- NX_IN_PROGRESS:(0x37) 斷開連線正在進行。
- NX_WAIT_ABORTED:(0x1A) 已通過呼叫 tx_thread_wait_abort 中止掛起請求。
- NX_PTR_ERROR:(0x07) Socket指標無效。
- NX_CALLER_ERROR:(0x11) 此服務的呼叫方無效。
- NX_NOT_ENABLED:(0x14) 此元件尚未啟用。
使用舉例:
/* 斷開連線 */ nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER);
9.3 TCP客戶端的實現方法
9.3.1 NetXDUO初始化
建立TCP伺服器前,要初始化NetX,建立記憶體池,例化IP:
/* ********************************************************************************************************* * 函 數 名: NetXTest * 功能說明: TCPnet應用 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void NetXTest(void) { UINT status; UINT ret; ULONG socket_state; UINT old_priority; NX_PACKET *data_packet; ULONG bytes_read; ULONG peer_ip_address; ULONG peer_port; /* 初始化NetX */ nx_system_initialize(); /* 建立記憶體池 */ status = nx_packet_pool_create(&pool_0, /* 記憶體池控制塊 */ "NetX Main Packet Pool",/* 記憶體池名 */ 1536, /* 記憶體池每個資料包大小,單位位元組此值必須至少為 40 個位元組,並且還必須可以被 4 整除 */ (ULONG*)(((int)packet_pool_area + 15) & ~15) ,/* 記憶體池地址,此地址必須ULONG對齊 */ NX_PACKET_POOL_SIZE); /* 記憶體池大小 */ /* 檢測建立是否失敗 */ if (status) error_counter++; /* 例化IP */ status = nx_ip_create(&ip_0, /* IP例項控制塊 */ "NetX IP Instance 0", /* IP例項名 */ IP_ADDRESS(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3), /* IP地址 */ 0xFFFFFF00UL, /* 子網掩碼 */ &pool_0, /* 記憶體池 */ nx_driver_stm32h7xx, /* 網絡卡驅動 */ (UCHAR*)AppTaskNetXStk, /* IP任務棧地址 */ sizeof(AppTaskNetXStk), /* IP任務棧大小,單位位元組 */ APP_CFG_TASK_NETX_PRIO); /* IP任務優先順序 */ /* 檢測建立是否失敗 */ if (status) error_counter++; /* 使能ARP,並提供ARP快取 */ status = nx_arp_enable(&ip_0, /* IP例項控制塊 */ (void *)arp_space_area, /* ARP快取地址 */ sizeof(arp_space_area)); /* 每個 ARP 條目均為 52 個位元組,因此,ARP 條目總數是52位元組整數倍 */ /* 使能fragment */ status = nx_ip_fragment_enable(&ip_0); /* 檢測使能成功 */ if (status) error_counter++; /* 使能TCP */ status = nx_tcp_enable(&ip_0); /* 檢測使能成功 */ if (status) error_counter++; /* 使能UDP */ status = nx_udp_enable(&ip_0); /* 檢測使能成功 */ if (status) error_counter++; /* 使能ICMP */ status = nx_icmp_enable(&ip_0); /* 檢測使能成功 */ if (status) error_counter++; /* NETX初始化完畢後,重新設定優先順序 */ tx_thread_priority_change(netx_thread_ptr, APP_CFG_TASK_NETX_PRIO1, &old_priority); tx_thread_priority_change(&AppTaskNetXProTCB, APP_CFG_TASK_NetXPro_PRIO1, &old_priority); /* 省略 */ }
程式末尾務優先順序做了特別處理,建立的時候先設定為低優先順序,檢測到網線正常連線並初始了網路後將優先順序設定到正常水平。
9.3.2 TCP客戶端實現
下面是建立TCP客戶端並遠端連線伺服器:
/* ********************************************************************************************************* * 函 數 名: NetXTest * 功能說明: TCPnet應用 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void NetXTest(void) { /* 省略 */ /* 建立TCP Socket */ ret = nx_tcp_socket_create(&ip_0, /* IP例項控制塊 */ &TCPSocket, /* TCP控制塊 */ "TCP Server Socket", /* TCP Socket名 */ NX_IP_NORMAL, /* IP服務型別 */ NX_FRAGMENT_OKAY, /* 使能IP分段 */ NX_IP_TIME_TO_LIVE, /*用於定義此資料包在被丟棄之前可通過的路由器數目 */ 4320, /* TCP Socket接收佇列中允許的最大位元組數 */ NX_NULL, /* 用於在接收流中檢測到緊急資料時呼叫的回撥函式 */ NX_NULL); /* TCP Socket另一端發出斷開連線時呼叫的回撥函式 */ if (ret) { Error_Handler(__FILE__, __LINE__); } /* * 監聽新的連結。 * 建立回撥TCP_listen_callback表示監聽到新連線。 */ ret = nx_tcp_server_socket_listen(&ip_0, /* IP例項控制塊 */ DEFAULT_PORT, /* 預設埠 */ &TCPSocket, /* TCP Socket控制塊 */ MAX_TCP_CLIENTS, /* 可以監聽的連線數 */ NULL); /* 監聽回撥函式 */ if (ret) { Error_Handler(__FILE__, __LINE__); } /* 啟動TCP通訊前,接收新連線 */ ret = nx_tcp_server_socket_accept(&TCPSocket, /* TCP Socket控制塊 */ TX_WAIT_FOREVER); /* 監聽回撥函式 */ if (ret) { Error_Handler(__FILE__, __LINE__); } /* 繫結埠 */ ret = nx_tcp_client_socket_bind(&TCPSocket, DEFAULT_PORT, NX_WAIT_FOREVER); if (ret != NX_SUCCESS) { Error_Handler(__FILE__, __LINE__); } /* 連線遠端伺服器 */ ret = nx_tcp_client_socket_connect(&TCPSocket, TCP_SERVER_ADDRESS, TCP_SERVER_PORT, NX_WAIT_FOREVER); if (ret != NX_SUCCESS) { Error_Handler(__FILE__, __LINE__); } /* 省略 */ }
9.3.3 TCP迴環通訊實現
迴環的意思就是電腦端網路助手傳送資料給板子後,板子再將資料返回。為了方便大家使用,本例子將接收資料包和傳送資料包分別做了定義:
/* ********************************************************************************************************* * 函 數 名: NetXTest * 功能說明: TCPnet應用 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void NetXTest(void) { /* 省略 */ while(1) { TX_MEMSET(data_buffer, '\0', sizeof(data_buffer)); /* 獲取socket狀態 */ nx_tcp_socket_info_get(&TCPSocket, /* TCP Socket控制塊 */ NULL, /* 傳送的TCP資料包總數目 */ NULL, /* 傳送的TCP總位元組數 */ NULL, /* 接收TCP資料包總數目 */ NULL, /* 接收的TCP總位元組數 */ NULL, /* 重新傳輸的TCP資料包總數目 */ NULL, /* Socket上TCP排隊的TCP資料包總數 */ NULL, /* Socket上有校驗和錯誤的TCP資料包總數 */ &socket_state, /* Socket當前狀態 */ NULL, /* 仍在排隊等待ACK的傳送資料包總數 */ NULL, /* 當前傳送視窗大小 */ NULL); /* 當前接收視窗大小 */ /* 如果連線還沒有建立,繼續接受新連線,成功的話開啟接收資料 */ if(socket_state != NX_TCP_ESTABLISHED) { /* 繫結埠 */ ret = nx_tcp_client_socket_bind(&TCPSocket, DEFAULT_PORT, NX_WAIT_FOREVER); if (ret != NX_SUCCESS) { Error_Handler(__FILE__, __LINE__); } /* 連線遠端伺服器 */ ret = nx_tcp_client_socket_connect(&TCPSocket, TCP_SERVER_ADDRESS, TCP_SERVER_PORT, NX_WAIT_FOREVER); if (ret != NX_SUCCESS) { Error_Handler(__FILE__, __LINE__); } } if((socket_state == NX_TCP_ESTABLISHED)&&(ret == NX_SUCCESS)) { /* 接收TCP客戶端發的TCP資料包 */ ret = nx_tcp_socket_receive(&TCPSocket, /* TCP Socket控制塊 */ &RecPacket, /* 接收到的資料包 */ NX_WAIT_FOREVER); /* 永久等待 */ if (ret == NX_SUCCESS) { /* 獲取客戶端的IP地址和埠 */ nx_tcp_socket_peer_info_get(&TCPSocket, /* TCP Socket控制塊 */ &peer_ip_address, /* 遠端IP地址 */ &peer_port); /* 遠端埠號 */ /* 獲取客戶端發來的資料 */ nx_packet_data_retrieve(RecPacket, /* 接收到的資料包 */ data_buffer, /* 解析出資料 */ &bytes_read); /* 資料大小 */ /* 列印接收到資料 */ PRINT_DATA(peer_ip_address, (unsigned int)peer_port, data_buffer); nx_packet_release(RecPacket); /* 申請傳送資料包 */ ret = nx_packet_allocate(&pool_0, &TraPacket, NX_TCP_PACKET, TX_WAIT_FOREVER); if (ret) { Error_Handler(__FILE__, __LINE__); } sprintf((char *)sendbuf, "sendbuf = %d\r\n", count++); /*將要傳送的資料附加到TraPacket */ ret = nx_packet_data_append(TraPacket, (VOID *)sendbuf, strlen((char *)sendbuf), &pool_0, TX_WAIT_FOREVER); if (ret) { Error_Handler(__FILE__, __LINE__); } /* 傳送資料,注意傳送後,此函式會釋放資料包 */ ret = nx_tcp_socket_send(&TCPSocket, TraPacket, NX_WAIT_FOREVER); if (ret) { //Error_Handler(__FILE__, __LINE__); } } else { /* 釋放資料包 */ nx_packet_release(RecPacket); /* 斷開連線 */ nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER); /* disconnect the socket */ nx_tcp_client_socket_unbind(&TCPSocket); } } } /* 省略 */ }
9.4 網路除錯助手和板子的除錯操作步驟
我們這裡使用下面這款除錯助手,當然,任何其它網路除錯助手均可,不限制:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=1568 。
9.4.1 測試使用的DM916X網口並注意跳線帽
測試時,網線要插到DM916X網口上:
特別注意此處跳線帽的位置,要短接PG11:
9.4.2 RJ45網路變壓器插座上綠燈和黃燈現象
各種網絡卡、交換機等網路裝置都不一樣,一般來講:綠燈分為亮或不亮(代表網路速度),黃燈分為閃爍或不閃爍(代表是否有資料收發)。
綠燈:長亮代表100M; 不亮代表10M。
黃燈:長亮代表無資料收發; 閃爍代表有資料收發。
也有些千兆網絡卡的燈以顏色區分,不亮代表10M / 綠色代表100M / 黃色代表1000M。現在10M的網路基本看不到了,如果一個燈長亮,基本可以說明100M網路或更高,而另一個燈時而閃爍,那代表有資料收發,具體要看網路裝置了。甚至有些低等網絡卡如TP-LINK,只有一個燈,亮代表連通,閃爍代表資料收發。
對於開發板上面的RJ45網路變壓器插座上面的燈而言,綠燈代表資料收發,長亮的話表示無資料收發,閃爍代表有資料收發。黃燈代表網路速度,長亮代表100M,不亮代表10M。
9.4.3 第1步,設定板子IP地址
我們這裡使用使用固定IP(或者說靜態IP一個意思),設定也比較省事。我們這裡以開發板和電腦直連的方式進行說明,即通過一根網線直接將開發板的網口和電腦端的網口連線起來即可。如果大家使用的是筆記本,強烈推薦測試期間將筆記本的WIFI網路禁止,各種代理軟體和虛擬網絡卡也暫時關閉。等測試完畢了再逐一開啟,檢視是否有問題。
對於固定IP方式,也可以接到路由器或者交換機上面測試,特別注意板子設定的IP地址不要跟路由器或者交換機上其它裝置的IP衝突了,測試階段還是建議採用電腦直連方式,跑通了再跑其它方式。
在檔案demo_dm9162_netx.h中設定IP地址,具體配置如下(大家更新自己的情況修改):
/* ********************************************************************************************************* * IP相關 ********************************************************************************************************* */ #define DEFAULT_PORT 1000 /* TCP伺服器監聽埠號 */ #define IP_ADDR0 192 #define IP_ADDR1 168 #define IP_ADDR2 28 #define IP_ADDR3 245
9.4.4 第2步,設定電腦IP地址
一定要將電腦端的IP地址設定到跟開發板在一個IP段,即都是192.168.28.X。第2步中已經將開發板的IP設定為192.168.28.245,我們這裡就將電腦的IP設定為192.168.28.221。我這裡是WIN7 64bit系統。
(1)右擊桌面上的“網路”圖示,選擇屬性。
(2)彈出的介面中選項“本地連線”
(3)選擇“屬性(P)”
(4)雙擊“Internet協議版本4(TCP/Ipv4)”選項。
(5)配置IP地址、子網掩碼和預設閘道器,DNS無需配置,記得點選確定
(6)點選了“確定”按鈕後,退回到之前的介面,這裡的“確定”按鈕不要忘了點選:
9.4.5 第3步,測試ping是否成功
下載例程到開發板,然後ping 192.168.28.245,檢視是否連線上。
(1)WIN+R組合鍵開啟“執行”視窗,輸入cmd。
(2)輸入ping 192.168.28.245後,回車,也是可以的。
收發相同,沒有資料丟失,說明ping命令也是成功的。
9.4.6 第4步,在程式中配置要訪問的遠端IP地址和埠
根據第2步設定的電腦端IP地址,需要大家配置程式中app_tcpnet_lib.c檔案開頭的巨集定義,其中IP地址填前面獲取的192.168.28.146,大家要根據電腦實際的IP地址填寫。而埠號,我們這裡隨意配置一個即可,配置為1001,後面電腦端使用網路除錯助手建立TCP伺服器時,務必要跟這個埠號統一:
/* 遠端伺服器埠和IP */ #define TCP_SERVER_PORT 1001 #define TCP_SERVER_ADDRESS IP_ADDRESS(192, 168, 28, 146)
9.4.7 第5步,網路除錯助手建立TCP伺服器
- 開啟除錯助手,點選左上角建立伺服器:
- 彈出如下介面,指定IP設定為192.168.28.146,一定要跟第2步設定的電腦IP地址一致,埠號1001,最後點選確定:
- 建立後的介面效果如下:
- 點選啟動伺服器:
9.4.8 第6步,建立TCP客戶端連線TCP伺服器
如果開發板下載了TCP客戶端的程式,並且開發板已經上電,可以看到客戶端連線已經加入:
跟我們在程式中設定的埠號,即app_tcpnet_lib.c檔案開頭的巨集定義:
#define DEFAULT_PORT 1000是一致的。
9.4.9 第5步,TCP客戶端迴環測試
板子和網路除錯助手建立連線後就可以相互收發資料了。
板子端接收到字元做了個簡單的展示(波特率115200,資料位8,奇偶校驗位無,停止位1):
9.5 實驗例程
配套例子:
V5-2403_ThreadX NetXDUO TCP Client
實驗目的:
- 學習ThreadX NetXDUO TCP 客戶端實現
實驗內容:
- 共建立瞭如下幾個任務,通過按下按鍵K1可以通過串列埠列印任務堆疊使用情況
======================================================
OS CPU Usage = 1.31%
=======================================================
任務優先順序 任務棧大小 當前使用棧 最大棧使用 任務名
Prio StackSize CurStack MaxStack Taskname
2 4092 303 459 App Task Start
30 1020 303 303 App Task STAT
31 1020 87 71 App Task IDLE
5 4092 311 551 App Msp Pro
7 4092 303 719 App Task UserIF
6 4092 255 359 App NETX Pro
3 4092 415 535 NetX IP Instance 0
0 1020 191 235 System Timer Thread
串列埠軟體可以使用SecureCRT或者H7-TOOL RTT檢視列印資訊。
App Task Start任務 :啟動任務,這裡用作BSP驅動包處理。
App Task MspPro任務 :訊息處理。
App Task UserIF任務 :按鍵訊息處理。
App Task COM任務 :這裡用作LED閃爍。
System Timer Thread任務:系統定時器任務
操作說明:
1、由於程式使用了DWT時鐘週期計數器,程式下載後,請將板子重新上電使用,防止DWT時鐘週期計數器沒有正常復位。
2、NetX網路協議棧操作:
(1) 預設IP地址192.168.28.245,在demo_dm9162_netx.c開頭定義,使用者可根據需要修改。
(2) 可以在電腦端用網路除錯軟體建立TCP伺服器,埠號1001。
(3) 實現了一個簡單的迴環通訊,使用者使用上位機發送的資料,然後板子返回另外的資料。
串列埠列印資訊方式(AC5,AC6和IAR):
波特率 115200,資料位 8,奇偶校驗位無,停止位 1
9.6 總結
本章節就為大家講解這麼多,希望大家多做測試,爭取可以熟練掌握這些API函式的使用。
微信公眾號:armfly_com 安富萊論壇:www.armbbs.cn 安富萊淘寶:https://armfly.taobao.com