PRJ - Ethernet Shield Chat Server#

From: Ethernet Shield Chat Server —— Arduino Documentation

功能#

ESP32 将作为一个简单的 Echo 服务器,接受来自以太网上的 Client 连接。

该服务器只能简单地将收到来自 Client 的消息原封不动的发送回去。并没有其它远程操作的功能。

注意: 一定要使用 Ethernet 扩展板,而不要拿 ESP32 的板子来替代,两者的网络库不同。

网络连接与 IP 地址#

将 ESP32 用网线连入 Client (PC) 所在的网络, Client 和 Server 的IP地址网络号要相同。

Code#

/*

 Chat Server
 A simple server that distributes any incoming messages to all
 connected clients.  To use, telnet to your device's IP address and type.
 You can see the client's input in the serial monitor as well.
 Using an Arduino Wiznet Ethernet shield.
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13

 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012

 by Tom Igoe
 */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network.
// gateway and subnet are optional:
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 100);
IPAddress myDns(192, 168, 1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 0, 0);

// telnet defaults to port 23
EthernetServer server(23);
bool alreadyConnected = false; // whether or not the client was connected previously

void setup()
{
  // You can use Ethernet.init(pin) to configure the CS pin
  // Ethernet.init(10);  // Most Arduino shields
  // Ethernet.init(5);   // MKR ETH shield
  // Ethernet.init(0);   // Teensy 2.0
  // Ethernet.init(20);  // Teensy++ 2.0
  // Ethernet.init(15);  // ESP8266 with Adafruit Featherwing Ethernet
  // Ethernet.init(33);  // ESP32 with Adafruit Featherwing Ethernet
  // initialize the ethernet device

  Ethernet.begin(mac, ip, myDns, gateway, subnet);
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial)
  {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // Check for Ethernet hardware present

  if (Ethernet.hardwareStatus() == EthernetNoHardware)
  {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true)
    {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }

  if (Ethernet.linkStatus() == LinkOFF)
  {
    Serial.println("Ethernet cable is not connected.");
  }

  // start listening for clients

  server.begin();
  Serial.print("Chat server address:");
  Serial.println(Ethernet.localIP());
}

void loop()
{
  // wait for a new client:
  EthernetClient client = server.available();
  // when the client sends the first byte, say hello:

  if (client)
  {
    if (!alreadyConnected)
    {
      // clear out the input buffer:
      client.flush();
      Serial.println("We have a new client");
      client.println("Hello, client!");
      alreadyConnected = true;
    }
    
    if (client.available() > 0)
    {
      // read the bytes incoming from the client:
      char thisChar = client.read();
      // echo the bytes back to the client:
      server.write(thisChar);
      // server.write(toUpperCase(thisChar));
      // echo the bytes to the server as well:
      Serial.write(thisChar);
    }
  }
}

用 Client 连接#

在电脑上,使用 Telnet 连接该 Server:

telnet 192.168.1.100

成功后会收到以下消息:

We have a new client

这就有点类似于 Telnet 服务器上的欢迎语。接下来可以任意输出一些字符,就可以看到输出了。

关键代码#

为了方便,摘出其中 Server 部分的代码。

    if (client.available() > 0)
    {
      // read the bytes incoming from the client:
      char thisChar = client.read();
      // echo the bytes back to the client:
      server.write(thisChar);                         // 1
      // echo the bytes to the server as well:
      Serial.write(thisChar);
    }

当服务器收到了来自 client 的任何消息后,它会先读 client 的消息, 接着回写该消息,并向 Serial 写该消息。

读和写消息是逐字符串的。

问题#

回显字符为什么是重复的?#

为什么在 Telnet Client 中看到的是两个字符重复?

其中第1个字符是我们在本 Client 的键盘输入,第2个字符是服务器回送回来的结果。

当把 // 1 行的代码作以下修改,就会更加明显地看出是这个原因。

server.write(toUpperCase(thisChar));

当我们加入更多的 write 语句后,回写的结果的逻辑就不是很清楚了。

write() 和 println() 有何区别?#

采用回写 println()write() 有何不同?

Next#

尝试让服务器在收到 time 文字后,回显当前时间。