概述
TCP/IP的概念是很大的一个概念,也是当今计算机网络世界中使用最为广泛的协议。它的规范横跨软硬件的很多内容,其中TCP与IP其实也是可以分开为两种协议,但那时多数情况下,他只是利用IP进行通信时所必须用到的协议群的统称。停!不再展开了,其实也和编程关系不大[/手动狗头]~
简单而言,这就是有一群人为了统一便于大家计算机之间的数据传输定下来的一个约定,大家都按照这个协议制造硬件(比如网卡)、编写软件。现在几乎全部的网络设备都支持TCP/IP协议,只有协议统一,数据才能在各类设备中通行无阻。
名词扫盲
IP地址,子网掩码、网关IP: 链接
TCP/IP详解:链接
TCP Client(客户端)
API 理解
1.1、连接服务器
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);
喜欢哪个用哪个 ~
1.2、连接状态
uint8_t connected();
断开连接返回值为False,反之为true。
1.3、监控端口数据
int available();
返回值为缓存区数据量大小。
1.4、读写数据
在 WiFiClient 类中有一系列的继承,我们来扒一扒 ~
class WiFiClient : public ESPLwIPClient
class ESPLwIPClient : public Client
class Client: public Stream
class Stream: public Print
以上时一条非常清晰的继承关系,介绍几个常用继承过来的函数。在 Stream 中:
bool find(const char *target);
bool find(const char *target, size_t length);
bool findUntil(const char *target, const char *terminator);
long parseInt();
float parseFloat();
virtual size_t readBytes(char *buffer, size_t length);
size_t readBytesUntil(char terminator, char *buffer, size_t length);
virtual String readString();
String readStringUntil(char terminator);
在Print中:
size_t print();
size_t println();
虽然有 wirte 和 read 两位老将,但是用起来难免有些烦人。以上的继承函数简明的完成数据的读取。
例子
#include <Arduino.h>
#include <WiFi.h>
//以下三个定义为调试定义
#define DebugBegin(baud_rate) Serial.begin(baud_rate)
#define DebugPrintln(message) Serial.println(message)
#define DebugPrint(message) Serial.print(message)
const char* ssid = "601b";
const char* password = "601601601";
const uint16_t port = 8888; //服务器端口
const char * host = "192.168.1.104"; //服务器 ip or dns
WiFiClient client;//创建一个tcp client连接
bool STAConnect(const char* ssid,const char* password ){
WiFi.disconnect();
DebugPrint("\nConnecting to ");
DebugPrintln(ssid);
// #ifdef staticIP
// WiFi.config(staticIP, gateway, subnet);
// #endif
WiFi.setHostname("ESP-1234");
WiFi.begin(ssid, password);
uint8_t i = 0;
while (WiFi.status() != WL_CONNECTED && i++ < 40) {
delay(500);
Serial.print(".");
}
if (i == 21) {
DebugPrint("Could not connect to");
DebugPrintln(ssid);
return false;
}
return true;
}
void TCPClientInit(){
client.connect(host, port); //tcp连接
DebugPrint("connecting to ");
DebugPrintln(host);
}
void TCPClientMonitor(){
if (!client.connected()) { //判断状态,若断开就尝试重连。
if(WiFi.status() != WL_CONNECTED){
WiFi.disconnect();
delay(10);
WiFi.begin(ssid, password);
DebugPrint("Wait for WiFi");
while (WiFi.status() != WL_CONNECTED ){
delay(500);
DebugPrint(".");
}
}
client.connect(host, port);
delay(500);
}
if(client.available()!=0)
{
//读取从server返回到响应数据
String line = client.readStringUntil('f'); // 从缓存区读取数据一直到’f‘字符
DebugPrintln(line);
client.println(String("get it")+line);
}
}
void setup() {
//设置串口波特率,以便打印信息
DebugBegin(9600);
//延时5s 为了演示效果
delay(50);
STAConnect(ssid,password);
TCPClientInit();
delay(500);
}
void loop() {
TCPClientMonitor();
}
TCP Server(服务器端)
API 理解
2.1、启动TcpServer
void begin(uint16_t port=0);
这里的port端口设置既可以在函数中设置,也可以在类申明中设置。
WiFiServer server(23);
// 相同于
WiFiServer server;
server.begin(23);
2.2、关闭小包合并
void setNoDelay(bool nodelay);
当 nodelay 为 true 时,关闭小包合并包功能,不会延时发送数据。
2.3 端口链接请求监控
bool hasClient();
当端口有新的client请求时,将会返回ture。
例子
#include <Arduino.h>
#include <WiFi.h>
//定义最多多少个client可以连接本server(不要超过4个)
#define MAX_SRV_CLIENTS 3
#define DebugBegin(baud_rate) Serial.begin(baud_rate)
#define DebugPrintln(message) Serial.println(message)
#define DebugPrint(message) Serial.print(message)
const char* ssid = "601b";
const char* password = "601601601";
//创建server 端口号是23
WiFiServer server;
//管理clients
WiFiClient serverClients[MAX_SRV_CLIENTS];
bool STAConnect(const char* ssid,const char* password ){
DebugPrint("\nConnecting to ");
DebugPrintln(ssid);
#ifdef staticIP
WiFi.config(staticIP, gateway, subnet);
#endif
WiFi.begin(ssid, password);
uint8_t i = 0;
while (WiFi.status() != WL_CONNECTED && i++ < 20) {
delay(500);
Serial.print(".");
}
if (i == 21) {
DebugPrint("Could not connect to");
DebugPrintln(ssid);
return false;
}
return true;
}
void TCPServerInit(){
//启动server
server.begin(23);
//关闭小包合并包功能,不会延时发送数据
server.setNoDelay(true);
DebugPrint("Ready! Use 'telnet ");
DebugPrint(WiFi.localIP());
DebugPrintln(" 23' to connect");
}
void TCPServerMonitor(){
uint8_t i;
//检测是否有新的client请求进来
if (server.hasClient()) {
for (i = 0; i < MAX_SRV_CLIENTS; i++) {
//释放旧无效或者断开的client
if (!serverClients[i] || !serverClients[i].connected()) {
if (serverClients[i]) {
serverClients[i].stop();
}
//分配最新的client
serverClients[i] = server.available();
DebugPrint("New client: ");
DebugPrint(i);
break;
}
}
//当达到最大连接数 无法释放无效的client,需要拒绝连接
if (i == MAX_SRV_CLIENTS) {
WiFiClient serverClient = server.available();
serverClient.stop();
DebugPrintln("Connection rejected ");
}
}
//检测client发过来的数据
for (i = 0; i < MAX_SRV_CLIENTS; i++) {
if (serverClients[i] && serverClients[i].connected()) {
if (serverClients[i].available()) {
//get data from the telnet client and push it to the UART
while (serverClients[i].available()) {
//发送到串口调试器
Serial.write(serverClients[i].read());
}
}
}
}
if (Serial.available()) {
//把串口调试器发过来的数据 发送给client
size_t len = Serial.available();
uint8_t sbuf[len];
Serial.readBytes(sbuf, len);
//push UART data to all connected telnet clients
for (i = 0; i < MAX_SRV_CLIENTS; i++) {
if (serverClients[i] && serverClients[i].connected()) {
serverClients[i].write(sbuf, len);
delay(1);
}
}
}
}
void setup() {
DebugBegin(9600);
STAConnect(ssid,password);
TCPServerInit();
}
void loop() {
TCPServerMonitor();
}
评论区