ESP8266--學習筆記(五)TCP通訊--TCP-Server
阿新 • • 發佈:2019-02-11
TCP Server模式
- ESP8266 工作在station模式下,需確認ESP8266已經分配到IP地址,在啟用server偵聽
- ESP8266 工作在Soft-AP 模式下,可以直接啟動server偵聽
TCP Server模式配置流程:
- 根據工作協議初始化espconn引數
- 註冊連線成功的回撥函式和連線失敗重新連線的回撥函式(espconn_regist_connectcb和espconn_regist_reconcb)
- 呼叫espconn_accept偵聽TCP連線
- TCP連線成功後,在連線成功的回撥函式(espconn_connect_callback)中,註冊接收資料的回撥函式,傳送資料成功的回撥函式和斷開連線的回撥函式(espconn_regist_recvcb,espconn_regist_sentcb和espconn_regist_disconcb)
一樣的借用WiFi掃描連線的基礎程式碼,並在WiFi連線的功能函式裡面新增TCP連線功能,WiFi連線在主入口函式中的業務程式碼
void ICACHE_FLASH_ATTR Wifi_conned(void *arg){
static uint8 count=0;
struct ip_info info; //用於獲取IP地址的資訊
uint8 status;
os_timer_disarm(&connect_timer);
count++;
status=wifi_station_get_connect_status();
if (status==STATION_GOT_IP){
os_printf("Wifi connect success!");
const char remote_ip[4]={192,168,1,103};//用於存放本地IP地址,一定要是自己的電腦真實的本地IP地址
wifi_get_ip_info(STATON_IF,&info);
//my_station_init((struct ip_addr *)remote_ip,&info.ip,1025);//Client端初始化主函式
my_server_init(&info.ip,1213 );//Server端初始化主函式
return;
}else{
if(count>=7){
os_printf("Wifi connect fail!");
return;
}
}
os_timer_arm(&connect_timer,2000,NULL);
}
user_main.c的所有程式碼:
* user_main.c
*
* Created on: 2017脛錨3脭脗14脠脮
* Author: yuanlifu
*/
#include "ets_sys.h"
#include "driver/uart.h"
#include "user_main.h"
#include "user_interface.h"
#include "client.h"
#include "server.h"
ETSTimer connect_timer;
void ICACHE_FLASH_ATTR Wifi_conned(void *arg){
static uint8 count=0;
uint8 opmode;
struct ip_info info; //用於獲取IP地址的資訊
uint8 status;
os_timer_disarm(&connect_timer);
count++;
status=wifi_station_get_connect_status();
if(status==STATION_GOT_IP){
os_printf("Wifi connect success!");
const char remote_ip[4]={192,168,1,103};//用於存放本地IP地址,一定要是自己的電腦真實的本地IP地址
wifi_get_ip_info(STATON_IF,&info);
opmode = wifi_get_opmode_default();
os_printf("\r\n當前的工作模式:%d\r\n",opmode);
//my_station_init((struct ip_addr *)remote_ip,&info.ip,1025);//Client端初始化主函式
my_server_init(&info.ip,1213);//Server端初始化主函式
return;
}else{
if(count>=7){
os_printf("Wifi connect fail!");
return;
}
}
os_timer_arm(&connect_timer,2000,NULL);
}
void ICACHE_FLASH_ATTR scan_done(void *arg,STATUS status){
uint8 ssid[33];
char temp[128];
struct station_config stationConf;
if (status == OK)
{
struct bss_info *bss_link = (struct bss_info *)arg;
bss_link = bss_link->next.stqe_next;//ignore first
while (bss_link != NULL)
{
os_memset(ssid, 0, 33);
if (os_strlen(bss_link->ssid) <= 32)
{
os_memcpy(ssid, bss_link->ssid, os_strlen(bss_link->ssid));
}
else
{
os_memcpy(ssid, bss_link->ssid, 32);
}
os_sprintf(temp,"+CWLAP:(%d,\"%s\",%d,\""MACSTR"\",%d)\r\n",
bss_link->authmode, ssid, bss_link->rssi,
MAC2STR(bss_link->bssid),bss_link->channel);
os_printf("%s",temp);
bss_link = bss_link->next.stqe_next;
}
os_memcpy(&stationConf.ssid, "MERCURY_2784", 32);
os_memcpy(&stationConf.password, "123456789", 64);
wifi_station_set_config_current(&stationConf);
wifi_station_connect();
os_timer_setfn(&connect_timer,Wifi_conned,NULL);
os_timer_arm(&connect_timer,2000,NULL);
}
else
{
// os_sprintf(temp,"err, scan status %d\r\n", status);
// uart0_sendStr(temp);
os_printf("%s","Error");
}
}
void to_scan(void) { wifi_station_scan(NULL,scan_done); }
void user_init(){
struct softap_config config;
uint8 opmode;
uart_init(115200,115200);
wifi_set_opmode(0x03);//設定為AP模式
opmode = wifi_get_opmode_default();
os_printf("\r\n當前的工作模式:%d\r\n",opmode);
wifi_softap_get_config(&config);
os_memcpy(config.ssid,"ESP8266",strlen("ESP8266"));
os_memcpy(config.password,"123456789",strlen("123456789"));
config.ssid_len = strlen("ESP8266");
wifi_softap_set_config(&config);
system_init_done_cb(to_scan);//掃描WiFi需要系統初始化完成之後
}
void user_rf_pre_init(){
}
接下來就是編寫TCP server的套路了
- 根據工作協議初始化espconn引數
- 註冊連線成功的回撥函式和連線失敗重新連線的回撥函式(espconn_regist_connectcb和espconn_regist_reconcb)
- 呼叫espconn_accept偵聽TCP連線
- TCP連線成功後,在連線成功的回撥函式(espconn_connect_callback)中,註冊接收資料的回撥函式,傳送資料成功的回撥函式和斷開連線的回撥函式(espconn_regist_recvcb,espconn_regist_sentcb和espconn_regist_disconcb)
server.h
/**
*server.h
**/
#ifndef APP_INCLUDE_SERVER_H
#define APP_INCLUDE_SERVER_H
#include "user_main.h"
#include "espconn.h"
#include "mem.h"
void my_server_init(struct ip_addr *local_ip,int port);
#endif/*APP_INCLUDE_SERVER_H*/
server.c
* server.c
*
* Created on: 2017年3月17日
* Author: yulifu
*/
#include "server.h"
void ICACHE_FLASH_ATTR server_recv(void *arg,
char *pdata,
unsigned short len){//接收資料的回撥函式
os_printf("收到PC發來的資料:%s\r\n",pdata);//將客戶端發過來的資料打印出來
espconn_sent((struct espconn *)arg,"傳送已經收到\r\n",strlen("傳送已經收到"));//往客戶機發送資料
}
void ICACHE_FLASH_ATTR server_sent(void *arg){//傳送資料成功的回撥函式
os_printf("傳送資料成功!!\r\n");
}
void ICACHE_FLASH_ATTR server_discon(void *arg){//斷開連線的回撥函式
os_printf("連線已經斷開\r\n");
}
void ICACHE_FLASH_ATTR server_listen(void *arg){//伺服器監聽函式
struct espconn *pespconn=arg;
espconn_regist_recvcb(pespconn,server_recv);//註冊一個接收資料的回撥函式
espconn_regist_sentcb(pespconn,server_sent);//註冊一個傳送資料成功的回撥函式
espconn_regist_disconcb(pespconn,server_discon);//註冊一個斷開連線的回撥函式
}
void ICACHE_FLASH_ATTR server_recon(void *arg,sint8 err){//重新連接回調函式
os_printf("連線錯誤,錯誤程式碼為:%s\r\n",err);//輸出重新連線的錯誤程式碼
}
void ICACHE_FLASH_ATTR my_server_init(struct ip_addr *local_ip,int port){
LOCAL struct espconn esp_conn;
esp_conn.type=ESPCONN_TCP;
esp_conn.state=ESPCONN_NONE;
esp_conn.proto.tcp=(esp_tcp *)os_malloc(sizeof(esp_tcp));
os_memcpy(esp_conn.proto.tcp->local_ip,local_ip,4);
esp_conn.proto.tcp->local_port=port;
//註冊連線成功的回撥函式和連線失敗重新連線的回撥函式
espconn_regist_connectcb(&esp_conn,server_listen);//註冊一個連線成功回撥函式
espconn_regist_reconcb(&esp_conn,server_recon);//註冊一個連線失敗重新連接回調函式
espconn_accept(&esp_conn);
}
———————————————————————————
效果:
PC端:
手機端APP效果:
找到了一份ESP8266關於TCP通訊的原始碼感覺還不錯,怕忘記了就把它放在這裡:
tcp.c
/*
* tcp.c
*
* Created on: 2017年3月23日
* Author: yuanlifu
*/
#include "ets_sys.h"
#include "osapi.h"
#include "user_interface.h"
#include "mem.h"
#include "espconn.h"
#include "driver/uart.h"
#include "tcp.h"
typedef enum
{
teClient,
teServer
}teType;
typedef struct
{
BOOL linkEn;
BOOL teToff;
uint8_t linkId;
teType teType;
uint8_t repeaTime;
uint8_t changType;
uint8 remoteIp[4];
int32_t remotePort;
struct espconn *pCon;
}linkConType;
typedef struct
{
BOOL linkEn;
BOOL teToff;
uint8_t linkId;
teType teType;
uint8_t repeaTime;
struct espconn *pCon;
} espConnectionType;
linkConType pLink;
espConnectionType user_contype;
static struct espconn *pTcpServer;
//os_event_t procTaskQueue[procTaskQueueLen];
bool Connect_break;
bool Send_Flag;
/*
* 函式名:void Wifi_AP_Init()
* 功能wifi_ap初始化
*/
void WIFIAPInit()
{
struct softap_config apConfig;
/***************************模式設定************************************/
if(wifi_set_opmode(SOFTAP_MODE)){ // 設定為AP模式
}else{
}
/***************************名字設通道置************************************/
os_bzero(&apConfig, sizeof(struct softap_config));
wifi_softap_get_config(&apConfig);
apConfig.ssid_len=7; //設定ssid長度
os_strcpy(apConfig.ssid,"213聯盟"); //設定ssid名字
os_strcpy(apConfig.password,"12345678"); //設定密碼
apConfig.authmode =3; //設定加密模式
ETS_UART_INTR_DISABLE(); //關閉串列埠中斷
wifi_softap_set_config(&apConfig); //配置
ETS_UART_INTR_ENABLE(); //開啟串列埠
}
/*
*函式名:void TcpServer_Listen_Recv(void *arg, char *pdata, unsigned short len)
*功能:接收監聽函式
*/
void TcpServer_Listen_Recv(void *arg, char *pdata, unsigned short len)
{
uart0_sendStr(pdata);
}
/*
* 函式名:void TcpServer_Listen_Recb(void *arg, sint8 errType)
* 功能:連線監聽函式
*/
void TcpServer_Listen_recon_cb(void *arg, sint8 errType)
{
struct espconn *pespconn = (struct espconn *)arg;
linkConType *linkTemp = (linkConType *)pespconn->reverse;
Connect_break=0;
}
/*
* 函式名:void Tcp_Server_Listen_discon_cb(void *arg)
* 功能:正常斷開時監聽函式
*/
void Tcp_Server_Listen_discon_cb(void *arg)
{
struct espconn *pespconn = (struct espconn *) arg;
linkConType *linkTemp = (linkConType *) pespconn->reverse;
Connect_break=0;
}
/*
* 函式名:void Tcp_Server_Listen_sent_cb(void *arg)
* 功能:傳送成功監聽函式
*/
void Tcp_Server_Listen_sent_cb(void *arg)
{
struct espconn *pespconn = (struct espconn *) arg;
linkConType *linkTemp = (linkConType *) pespconn->reverse;
Send_Flag=0;
}
/*
* 函式名:void TcpServer_Listen_PCon(void *arg)
* 功能:手機連入AP監聽函式
*/
void TcpServerListen_PCon(void *arg)
{
struct espconn *pespconn = (struct espconn *)arg;
pLink.teToff = FALSE;
pLink.linkId = 1;
pLink.teType = teServer;
pLink.repeaTime = 0;
pLink.pCon = pespconn;
pespconn->reverse = &pLink;
espconn_regist_recvcb(pespconn, TcpServer_Listen_Recv); //註冊接收監聽函式
espconn_regist_reconcb(pespconn, TcpServer_Listen_recon_cb); //註冊連線監聽函式
espconn_regist_disconcb(pespconn, Tcp_Server_Listen_discon_cb); //註冊正常斷開時監聽函式
espconn_regist_sentcb(pespconn, Tcp_Server_Listen_sent_cb); //註冊傳送成功監聽函式
}
/*
* 函式名:void WIFI_Server_MODE()
* 功能:設定伺服器模式
*/
void WIFIServerMode(void)
{
espconn_tcp_set_max_con(1); //設定TCP連線的最大多少
pTcpServer = (struct espconn *)os_zalloc(sizeof(struct espconn));
pTcpServer->type = ESPCONN_TCP; //TCP服務
pTcpServer->state = ESPCONN_NONE; //狀態
pTcpServer->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
pTcpServer->proto.tcp->local_port = 8888; //斷開號
espconn_regist_connectcb(pTcpServer, TcpServerListen_PCon);
espconn_accept(pTcpServer);
espconn_regist_time(pTcpServer, 180, 0); //設定超時斷開時間 單位s
}
/*
* 函式名:void WIFI_TCP_SendNews(unsigned char *dat)
* 功能:像TCP伺服器傳送訊息
*/
void WIFI_TCP_SendNews(unsigned char *dat,uint16 len)
{
espconn_sent(pLink.pCon,dat,len);
}
/*void SendTask(os_event_t *events)
{
struct station_info *pstation_info=wifi_softap_get_station_info();
if((pstation_info!=NULL)&&(Connect_break==1)){
if(Send_Flag==0){
Send_Flag=1;
WIFI_TCP_Send(xReceive,xLen);
}else{
uart0_sendStr("bus");
}
}else{
Send_Flag=0;
uart0_sendStr("NO device");
}
xLen=0;
}
void Task_Init()
{
// uart_init(BIT_RATE_9600,BIT_RATE_9600);
system_os_task(SendTask, procTaskPrio, procTaskQueue, procTaskQueueLen);
}*/
tcp.h
/*
* tcp.h
*
* Created on: 2017年3月23日
* Author: yuanlifu
*/
#ifndef APP_USER_TCP_H_
#define APP_USER_TCP_H_
void WIFIAPInit();
void WIFIServerMode(void);
void TcpServerListen_PCon(void *arg);
void WIFI_TCP_SendNews(unsigned char *dat,uint16 len);
//void Task_Init();
#endif /* APP_USER_TCP_H_ */