使用Arduino开发ESP32(08):TCP Client与TCP Server使用

目的

TCP是网络应用中经常使用的功能,不少高级功能也是创建在TCP的基础上的,学会使用TCP就能够开发不少网络应用了。html

TCP Client

TCP Client主要是用来访问服务器的,不少能够经过外网访问的物联网设备主要就是工做在TCP Client下。设备主动去访问外部的服务器,与服务器创建链接,用户的app也是去访问这个服务器,这样变相实现了用户对设备的访问。node

使用说明

TCP Client按以下方式使用:git

  1. 引用相关库#include <WiFi.h>
  2. 连上网(好像是一句废话)
  3. 声明WiFiClient对象用于链接服务器;
  4. 使用connect方法链接服务器;
  5. 进行数据读写通信;

经常使用方法

  • int connect(IPAddress ip, uint16_t port)
    int connect(IPAddress ip, uint16_t port, int32_t timeout)
    int connect(const char *host, uint16_t port)
    int connect(const char *host, uint16_t port, int32_t timeout)
    用于和服务器创建链接,能够链接指定IP地址或是指定域名,链接成功返回1,失败返回0;
  • size_t write(uint8_t data)
    size_t write(const uint8_t *buf, size_t size)
    size_t write_P(PGM_P buf, size_t size)
    size_t write(Stream &stream)
    发送数据,发送成功返回发送字节数,失败返回0;
    除了用write()方法外也能够用print()等方法发送数据;
  • int available()
    返回可读取数据长度,若是没有数据可读取则返回0;
  • int read()
    int read(uint8_t *buf, size_t size)
    从接收缓存读取数据并返回读取到的数据字节数,若是返回-1则表示读取失败,读取过的数据会从接收缓存删除;
  • int peek()
    读取首字节数据,但并不从接收缓存中删除它;
  • void flush()
    清空当前接收缓存;
  • void stop()
    关闭客户端,释放资源;
  • uint8_t connected()
    返回当前客户端是否与服务器创建链接;
  • IPAddress remoteIP() const
    IPAddress remoteIP(int fd) const
    返回服务器IP地址;
  • uint16_t remotePort() const
    uint16_t remotePort(int fd) const
    返回服务器端口号;
  • IPAddress localIP() const
    IPAddress localIP(int fd) const
    返回本地IP地址;
  • uint16_t localPort() const
    uint16_t localPort(int fd) const
    返回本地端口号;

基础使用演示

使用下面代码进行测试:github

#include <WiFi.h>

const char *ssid = "********";
const char *password = "********";

const IPAddress serverIP(192,168,50,14); //欲访问的地址
uint16_t serverPort = 50037;         //服务器端口号

WiFiClient client; //声明一个客户端对象,用于与服务器进行链接

void setup()
{
    Serial.begin(115200);
    Serial.println();

    WiFi.mode(WIFI_STA);
    WiFi.setSleep(false); //关闭STA模式下wifi休眠,提升响应速度
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }
    Serial.println("Connected");
    Serial.print("IP Address:");
    Serial.println(WiFi.localIP());
}

void loop()
{
    Serial.println("尝试访问服务器");
    if (client.connect(serverIP, serverPort)) //尝试访问目标地址
    {
        Serial.println("访问成功");

        client.print("Hello world!");                    //向服务器发送数据
        while (client.connected() || client.available()) //若是已链接或有收到的未读取的数据
        {
            if (client.available()) //若是有数据可读取
            {
                String line = client.c('\n'); //读取数据到换行符
                Serial.print("读取到数据:");
                Serial.println(line);
                client.write(line.c_str()); //将收到的数据回发
            }
        }
        Serial.println("关闭当前链接");
        client.stop(); //关闭客户端
    }
    else
    {
        Serial.println("访问失败");
        client.stop(); //关闭客户端
    }
    delay(5000);
}

在这里插入图片描述
上图中咱们用工具创建的TCP Server进行测试;web

做为WEB Client使用

使用下面代码进行测试:浏览器

#include <WiFi.h>

const char *ssid = "********";
const char *password = "********";

const char *host = "www.example.com"; //欲访问的域名

void setup()
{
    Serial.begin(115200);
    Serial.println();

    WiFi.mode(WIFI_STA);
    WiFi.setSleep(false); //关闭STA模式下wifi休眠,提升响应速度
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }
    Serial.println("Connected");
    Serial.print("IP Address:");
    Serial.println(WiFi.localIP());
}

void loop()
{
    WiFiClient client; //声明一个客户端对象,用于与服务器进行链接

    Serial.println("尝试访问服务器");
    if (client.connect(host, 80)) //80为通常网站的端口号
    {
        Serial.println("访问成功");

        //向服务器发送请求头,请求网页数据
        //******做为WEB Client使用最核心的就是和WEB Server链接成功后发送相应的请求头请求数据******
        //******WEB Server在收到请求头后返回对应的数据,好比返回网页、图片、文本等******
        //******关于请求头能够参考以前的文章《从零开始的ESP8266探索(06)-使用Server功能搭建Web Server》******
        client.print(String("GET /") + " HTTP/1.1\r\n" +
                     "Host: " + host + "\r\n" +
                     "Connection: close\r\n" +
                     "\r\n");

        //如下代码将收到的网页数据按行打印输出
        //若是是常见的WEB Client(浏览器)的话会将收到的html文件渲染成咱们通常看到的网页
        while (client.connected() || client.available()) //若是已链接或有收到的未读取的数据
        {
            if (client.available()) //若是有数据可读取
            {
                String line = client.readStringUntil('\n'); //按行读取数据
                Serial.println(line);
            }
        }

        client.stop(); //关闭当前链接
    }
    else
    {
        Serial.println("访问失败");
        client.stop(); //关闭当前链接
    }
    delay(10000);
}

在这里插入图片描述
上图测试中(虽然是拿了之前的图,但结果是同样的)咱们首先去访问 www.example.com(该网址是专门用于测试的),在链接成功后咱们向服务器发送请求头请求网页数据,服务器在收到请求头向咱们返回了响应头和网页数据(数据能够参考下图,你也能够在浏览器中打开此页面而后右击查看源代码);
在这里插入图片描述缓存

TCP Server

使用说明

TCP Server按以下方式使用:安全

  • 引用相关库#include <WiFi.h>
  • 声明WiFiServer对象;
  • 使用begin方法启动监听;
  • 监听客户端链接并处理数据通信;

经常使用方法

  • WiFiServer(uint16_t port=80, uint8_t max_clients=4)
    在声明WiFiServer对象能够选择输入要监听的端口号和最大接入客户数量;
  • WiFiClient available()
    WiFiClient accept(){return available();}
    尝试创建客户对象;
  • void begin(uint16_t port=0)
    服务器启动监听;
  • void setNoDelay(bool nodelay)
    设置是否延时发送(使用begin方法时会被设置为false,这样服务器会合并小数据包后发送,产生延时);
    开启NoDelay能够提升应答速度,但有些状况下会下降总传输效率,须要根据需求设置;
  • bool getNoDelay()
    返回是否延时发送;
  • bool hasClient()
    返回是否有客户端尝试接入;
  • size_t write(const uint8_t *data, size_t len)
    size_t write(uint8_t data){return write(&data, 1);}
    发送数据,发送成功返回发送字节数,失败返回0;
    除了用write()方法外也能够用print()等方法发送数据;
  • void end()
    void close()
    void stop()
    中止当前监听;
  • int setTimeout(uint32_t seconds)
    设置超时时间;

基础使用演示

使用下面代码进行测试:服务器

#include <WiFi.h>

const char *ssid = "********";
const char *password = "********";

WiFiServer server; //声明服务器对象

void setup()
{
    Serial.begin(115200);
    Serial.println();

    WiFi.mode(WIFI_STA);
    WiFi.setSleep(false); //关闭STA模式下wifi休眠,提升响应速度
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }
    Serial.println("Connected");
    Serial.print("IP Address:");
    Serial.println(WiFi.localIP());

    server.begin(22333); //服务器启动监听端口号22333
}

void loop()
{
    WiFiClient client = server.available(); //尝试创建客户对象
    if (client) //若是当前客户可用
    {
        Serial.println("[Client connected]");
        String readBuff;
        while (client.connected()) //若是客户端处于链接状态
        {
            if (client.available()) //若是有可读数据
            {
                char c = client.read(); //读取一个字节
                                        //也能够用readLine()等其余方法
                readBuff += c;
                if(c == '\r') //接收到回车符
                {
                    client.print("Received: " + readBuff); //向客户端发送
                    Serial.println("Received: " + readBuff); //从串口打印
                    readBuff = "";
                    break; //跳出循环
                }
            }
        }
        client.stop(); //结束当前链接:
        Serial.println("[Client disconnected]");
    }
}

在这里插入图片描述

做为WEB Server使用

后面会介绍更加方便的WebServer功能,若是想用TCP Server实现这个的话能够参考官方例程:
https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFi/examples/SimpleWiFiServer
或是下面文章:
《从零开始的ESP8266探索(06)-使用Server功能搭建Web Server》网络

总结

TCP Client与TCP Server的基本使用主要就是上面这些了,结合以前的UDP功能,已经能够开发不少网络应用了。更多内容能够参考以下:
https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFi
另外若是做为客户端使用有安全方面需求能够参考下面链接:
https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFiClientSecure

The WiFiClientSecure class implements support for secure connections using TLS (SSL). It inherits from WiFiClient and thus implements a superset of that class’ interface. There are three ways to establish a secure connection using the WiFiClientSecure class: using a root certificate authority (CA) cert, using a root CA cert plus a client cert and key, and using a pre-shared key (PSK).