最近再研究 rt-thread 的通信 ,想設(shè)計(jì)出 eps8266(多個(gè))<-> rt-thread(作為中控) <-> 服務(wù)器的通信框架,使用的開發(fā)板是 潘多拉
首先我們需要 確保使用的開發(fā)板可以聯(lián)網(wǎng),其次 我們需要在rt-setting 中打開套接字抽象層
如圖
下載樣例后,把IoT_Boardrt-threadexamplesnetwork 下的tcpserver.c 和 tcpclient.c拿出來放到我們的工程中。
這兩個(gè)文件提供了tcp連接指令給我們
具體使用方法如圖。
在進(jìn)行下一步前最好測試一下這兩個(gè)指令是否生效。
為了接下來能看懂,我這邊簡單介紹一些 esp8266的邏輯 ,
連接wifi -> 連接終端(即rt-thread)->首次連接發(fā)送設(shè)備id-> 循環(huán)查看是否接受到數(shù)據(jù),如果接收到即對指令進(jìn)行處理,否則發(fā)送當(dāng)前設(shè)備的狀態(tài)
接下來看一下終端這邊的邏輯,終端首先要連接wifi ,之后提供 tcpserver 等待 esp8266連接,在esp8266連接上后,創(chuàng)建一個(gè)線程,線程名為設(shè)備id,再將線程socket資源放到一個(gè)全局結(jié)構(gòu)體中,用于之后的維護(hù)。
Tcpserver.c 中沒有多少修改的,我只粘貼修改的部分
在tcpserv函數(shù)中,在receive 后修改如下
bytes_received = recv(connected, str, BUFSZ, 0);
if (bytes_received < 0)
{
LOG_E("Received error, close the connect.");
closesocket(connected);
connected = -1;
break;
}
else
{
/* 在控制終端顯示收到的數(shù)據(jù) */
rt_thread_t tid;
LOG_D("Received threadName = %s n", str,str);
tid = rt_thread_create(str,
tcpserver_to_client, (void *)connected,
1024, RT_THREAD_PRIORITY_MAX/3, 20);
if (tid != RT_NULL)
{
sockets.tids[sockets.len]=tid;
sockets.connects[sockets.len]=connected;
sockets.len++;
rt_thread_startup(tid);
}
}
即和上面的邏輯一樣,創(chuàng)建通信的線程,將線程資源和socket資源放到全局結(jié)構(gòu)體中維護(hù),結(jié)構(gòu)體的定義如下
接下來看通信線程,代碼如下
static void tcpserver_to_client(void conn){
int running=1;
int bytes_received,connected;
char str[20];
connected = (int)conn;
/ 客戶端連接的處理 /
while (running)
{
/ 從connected socket中接收數(shù)據(jù),接收buffer是1024大小,但并不一定能夠收到1024大小的數(shù)據(jù) /
bytes_received = recv(connected, str, BUFSZ, 0);
if (bytes_received < 0)
{
LOG_E("Received error, close the connect.");
closesocket(connected);
connected = -1;
return ;
}
else
{
/ 在控制終端顯示收到的數(shù)據(jù) */
rt_mb_send(&mb, (rt_uint32_t)&str);
}
}
}
在這個(gè)線程中,通過傳遞的socket資源,接受數(shù)據(jù),注意這邊的recv是阻塞的,如果接受到數(shù)據(jù),就將數(shù)據(jù)發(fā)送到郵箱中,這邊為什么要使用郵箱呢,以為后續(xù)我們需要和tcpclient線程進(jìn)行通信,在esp8266發(fā)送消息給我們后,我們需要將消息轉(zhuǎn)發(fā)給服務(wù)器。
在繼續(xù)講解rt-thread邏輯前我們來看一下服務(wù)器的邏輯,服務(wù)器邏輯比較簡單,就是提供sever服務(wù),接受tcpclient的數(shù)據(jù),并且給tcpclient發(fā)送消息,注意服務(wù)器端的recv是非阻塞的
接下來看tcpclient的邏輯,在tcpclient中,我們既需要將esp8266的數(shù)據(jù)轉(zhuǎn)發(fā)給服務(wù)器,也需要接受服務(wù)器傳的數(shù)據(jù),所以我們在這邊的recv不能是阻塞的,那怎么將esp8266的消息轉(zhuǎn)發(fā)呢,就是用之前的郵箱來通信啦,代碼如下
while (is_running)
{
/* 從sock連接中接收最大BUFSZ - 1字節(jié)數(shù)據(jù) /
bytes_received = recv(sock, recv_data, BUFSZ - 1, MSG_DONTWAIT);
if (bytes_received > 0)
{
char threadName[10]={0};
rt_strncpy(threadName, recv_data, 4);
/ 有接收到數(shù)據(jù),把末端清零 /
recv_data[bytes_received] = '?';
/ 在控制終端顯示收到的數(shù)據(jù) /
rt_kprintf("Received data = %sn", recv_data);
send_client(threadName,recv_data);
}
if(get_mailbox()==RT_TRUE){
/ 發(fā)送數(shù)據(jù)到sock連接 /
ret = send(sock, str, rt_strlen(str), 0);
if (ret < 0)
{
/ 接收失敗,關(guān)閉這個(gè)連接 /
rt_kprintf("send error, close the socket.");
goto __exit;
}
else if (ret == 0)
{
/ 打印send函數(shù)返回值為0的警告信息 */
rt_kprintf("Send warning, send function return 0.");
}
}
rt_thread_mdelay(3000);
}
在這段代碼中,recv 的flag 改成了MSG_DONTWAIT 這是revc非阻塞的標(biāo)志,
比較關(guān)鍵的是recv后面的內(nèi)容,在接受數(shù)據(jù)后,會(huì)取出數(shù)據(jù)的前四位(前四位為設(shè)備id),并且通過send_client 來判斷,如果前四位和之前創(chuàng)建的線程名一樣,就把數(shù)據(jù)發(fā)送給對應(yīng)的設(shè)備send_client函數(shù)如下
void send_client(char threadName[],char recvData[]){
int i,ret;
for(i=0;i {
if(rt_strcmp(threadName, (sockets.tids[i])->name)==0){
rt_kprintf("find order to %sn",threadName);
ret = send(sockets.connects[i], recvData, rt_strlen(recvData), 0);
if (ret < 0)
{
/* 接收失敗,關(guān)閉這個(gè)連接 /
rt_kprintf("send error n");
}
else if (ret == 0)
{
/ 打印send函數(shù)返回值為0的警告信息 */
rt_kprintf("Send warning, send function return 0.n");
}
}
}
}
get_mailbox()函數(shù)是判斷郵箱中是否有東西,有的話就放到str中,并且發(fā)送給服務(wù)器get_mailbox 函數(shù)代碼如下
static int get_mailbox(){
if (rt_mb_recv(&mb, (rt_ubase_t *)&str, RT_WAITING_NO) == RT_EOK)
{
rt_kprintf("thread1: get a mail from mailbox, the content:%d, str1= %sn",str,str);
return RT_TRUE;
}
return RT_FALSE;
}
以上就是實(shí)現(xiàn)的流程了,其實(shí)還是比較簡單的。
-
控制器
+關(guān)注
關(guān)注
114文章
16959瀏覽量
182870 -
Socket
+關(guān)注
關(guān)注
1文章
212瀏覽量
35545 -
RT-Thread
+關(guān)注
關(guān)注
32文章
1368瀏覽量
41501 -
ESP8266
+關(guān)注
關(guān)注
51文章
965瀏覽量
46867 -
TCP通信
+關(guān)注
關(guān)注
0文章
146瀏覽量
4461
發(fā)布評論請先 登錄
RT-Thread記錄(二、RT-Thread內(nèi)核啟動(dòng)流程)

求一種基于RT-Thread的socket通信方案
RT-Thread編程指南
RT-Thread用戶手冊
RT-Thread全球技術(shù)大會(huì):螢石研發(fā)團(tuán)隊(duì)使用RT-Thread的技術(shù)挑戰(zhàn)

RT-Thread全球技術(shù)大會(huì):Kconfig在RT-Thread中的工作機(jī)制

RT-Thread全球技術(shù)大會(huì):在RT-Thread上編寫測試用例

RT-Thread全球技術(shù)大會(huì):RT-Thread測試用例集合案例

RT-Thread學(xué)習(xí)筆記 RT-Thread的架構(gòu)概述

RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南

基于RT-Thread Studio學(xué)習(xí)

評論