Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:WebSocket和EventSource

2023-10-27

目的

WebSocket和EventSource是HTML5开始提供的功能。WebSocket可以在单个TCP连接上进行全双工通讯;EventSource可以由服务器主动向客户端推送消息。两个功能可以大大提升web应用的数据交互的性能。这篇文章将介绍ESPAsyncWebServer库中这两个功能的使用方式。

本文中各例程演示均在ESP32中进行。

WebSocket

使用方法

WebSocket使用并不复杂,除了正常的声明与初始化AsyncWebServer对象外,只需下面几步即可:

  • 声明 AsyncWebSocket 对象与URL;
  • 绑定 AsyncWebSocket 对象事件回调函数;
  • AsyncWebSocket 对象添加到服务器中;

使用演示

使用下面代码进行测试:

#include <WiFi.h>
#include <ESPAsyncWebServer.h> //引入相应库

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

// 以下为网页文件
String indexhtml = String("") +
                   "<!DOCTYPE html> \n" +
                   "<html> \n" +
                   "<head> \n" +
                   "    <meta charset=\"UTF-8\"> \n" +
                   "    <title>WebSocket Test</title> \n" +
                   "    <script> \n" +
                   "        var ws; \n" +
                   "        window.onload = function () { \n" +
                   "            if (\"WebSocket\" in window) { \n" +
                   "                ws = new WebSocket(\"ws://\" + window.location.host + \"/\"); // 建立WebSocket连接 \n" +
                   "                ws.onopen = function () { // 连接建立成功时触发 \n" +
                   "                    document.getElementById(\"info\").innerHTML += \"WebSocket连接成功!\" + \"<br>\"; \n" +
                   "                    ws.send(\"connect ok!\"); // 向服务器发送数据 \n" +
                   "                }; \n" +
                   "                ws.onmessage = function (evt) { // 收到服务器数据时触发 \n" +
                   "                    document.getElementById(\"info\").innerHTML += evt.data + \"<br>\"; \n" +
                   "                }; \n" +
                   "                ws.onerror = function () { // 发生错误时触发 \n" +
                   "                    document.getElementById(\"info\").innerHTML += \"通讯发送错误!\" + \"<br>\"; \n" +
                   "                }; \n" +
                   "                ws.onclose = function () { // 连接关闭时触发 \n" +
                   "                    document.getElementById(\"info\").innerHTML += \"WebSocketTest连接已关闭!\" + \"<br>\"; \n" +
                   "                }; \n" +
                   "            } \n" +
                   "            else { \n" +
                   "                document.getElementById(\"info\").innerHTML = \"浏览器不支持 WebSocket!\"; \n" +
                   "            } \n" +
                   "        }; \n" +
                   "        function send() { \n" +
                   "            console.log(\'error\'); \n" +
                   "            ws.send(\"hahaha~~~\"); // 向服务器发送数据 \n" +
                   "        } \n" +
                   "    </script> \n" +
                   "</head> \n" +
                   "<body> \n" +
                   "    <button οnclick=\"send()\">点击向服务器发送数据</button> \n" +
                   "    <div id=\"info\"></div> \n" +
                   "</body> \n" +
                   "</html> \n";

AsyncWebServer server(80); // 声明WebServer对象

AsyncWebSocket ws("/"); // WebSocket对象,url为/

// WebSocket事件回调函数
void onEventHandle(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
{
  if (type == WS_EVT_CONNECT) // 有客户端建立连接
  {
    Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
    client->printf("Hello Client %u !", client->id()); // 向客户端发送数据
    client->ping();                                    // 向客户端发送ping
  }
  else if (type == WS_EVT_DISCONNECT) // 有客户端断开连接
  {
    Serial.printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id());
  }
  else if (type == WS_EVT_ERROR) // 发生错误
  {
    Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data);
  }
  else if (type == WS_EVT_PONG) // 收到客户端对服务器发出的ping进行应答(pong消息)
  {
    Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len) ? (char *)data : "");
  }
  else if (type == WS_EVT_DATA) // 收到来自客户端的数据
  {
    AwsFrameInfo *info = (AwsFrameInfo *)arg;
    Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT) ? "text" : "binary", info->index, info->index + len);
    data[len] = 0;
    Serial.printf("%s\n", (char *)data);
  }
}

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

  WiFi.mode(WIFI_STA);
  WiFi.setSleep(false);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected");
  Serial.print("IP Address:");
  Serial.println(WiFi.localIP());

  ws.onEvent(onEventHandle); // 绑定回调函数
  server.addHandler(&ws);    // 将WebSocket添加到服务器中

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { //注册链接"/lambda"与对应回调函数(匿名函数形式声明)
    request->send(200, "text/html", indexhtml);                 //向客户端发送响应和内容
  });

  server.begin(); //启动服务器

  Serial.println("Web server started");
}

void loop()
{
  delay(2000);
  ws.textAll("lalala~~~"); // 向所有建立连接的客户端发送数据
  ws.cleanupClients();     // 关闭过多的WebSocket连接以节省资源
}

上面的代码直接拷贝可能网页的字符串部分代码会出现编码问题导致无法正确运行,该部分最好删除重新手打。如果想偷懒的话可以试试只删除 onclick 这个词的 o 然后手打输入。
在这里插入图片描述
上面就是一个使用WebSocket进行双向通讯的例子,所有的关键步骤都在上面代码中写了注释。可以看到使用WebSocket进行数据交互比传统的用Ajax的方式要方便多了。

更多说明

WebSocket用于双向通讯,服务器端接收来自客户端的消息上面已经进行了演示,是在事件回调函数中进行的,同时在回调函数中也可以通过AsyncWebSocketClient对象发送消息,主要方式如下:

  • 格式化输出方式:
    size_t printf(const char *format, ...) __attribute__ ((format (printf, 2, 3)));
    size_t printf_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3))); // ESP32特有
  • 文本数据输出方式:
    void text(const char * message, size_t len);
    void text(const char * message);
    void text(uint8_t * message, size_t len);
    void text(char * message);
    void text(const String &message);
    void text(const __FlashStringHelper *data);
    void text(AsyncWebSocketMessageBuffer *buffer);
  • 二进制数据输出方式:
    void binary(const char * message, size_t len);
    void binary(const char * message);
    void binary(uint8_t * message, size_t len);
    void binary(char * message);
    void binary(const String &message);
    void binary(const __FlashStringHelper *data, size_t len);
    void binary(AsyncWebSocketMessageBuffer *buffer);

AsyncWebSocketClient对象除了可以用来发送数据,还可以获得一些信息 IPAddress remoteIP();uint16_t remotePort();,可以使用 void ping(uint8_t *data=NULL, size_t len=0); 方法向客户端发送ping信息,可以使用 void keepAlivePeriod(uint16_t seconds) 设置定时自动发送ping。最后可以用 void close(uint16_t code=0, const char * message=NULL); 方法关闭当前建立的连接。

除了上面客户端对象可以用来发送数据,AsyncWebSocket对象自身也可以发送数据,发送方法和客户端对象差不多,只不过第一个参数新增了客户端id:

  • size_t printf(uint32_t id, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
    ……
  • void text(uint32_t id, const char * message, size_t len);
    ……
  • void binary(uint32_t id, const char * message, size_t len);
    ……

此外AsyncWebSocket对象还可以同时向全体已连接的客户端发送消息,方法和上面的差不多,主要是不需要id,然后方法名后跟上All:

  • size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3)));
    ……
  • void textAll(const char * message, size_t len);
    ……
  • void binaryAll(const char * message, size_t len);
    ……

AsyncWebSocket对象除了上面这些发送消息的功能外还有一些其它方法,可以用 size_t count() const; 获取已连接客户端数量,可以用 bool hasClient(uint32_t id){ return client(id) != NULL; } 判断是否有指定客户端,可以用 void ping(uint32_t id, uint8_t *data=NULL, size_t len=0);void pingAll(uint8_t *data=NULL, size_t len=0); 发送ping信息。最后可以用 void close(uint32_t id, uint16_t code=0, const char * message=NULL);void closeAll(uint16_t code=0, const char * message=NULL); 关闭客户端连接。
另外对于AsyncWebSocket对象还有一个特殊的方法:void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS);。该方法上面演示中也有用到,依据建立事件,从最早的开始关闭超出设定数量的客户端连接。(主要是芯片性能有限,无限制的建立长连接可能就无法正常工作了。默认情况下ESP32可以建立32个连接、ESP8266可以建立8个连接。)

EventSource

使用方法

EventSource的使用比较简单,除了正常的声明与初始化AsyncWebServer对象外,只要下面几步就可以使用了:

  • 声明 AsyncEventSource 对象与URL;
  • 绑定 AsyncEventSource 对象事件回调函数; (可选)
  • AsyncEventSource 对象添加到服务器中;

使用演示

使用下面代码进行测试:

#include <WiFi.h>
#include <ESPAsyncWebServer.h> //引入相应库

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

// 以下为网页文件
String indexhtml = String("") +
                   "<!DOCTYPE html>\n" +
                   "<head>\n" +
                   "    <meta charset=\"UTF-8\">\n" +
                   "    <title>EventSource Test</title>\n" +
                   "</head>\n" +
                   "<body>\n" +
                   "    <div id=\"info\"></div>\n" +
                   "    <script>\n" +
                   "        if (typeof (EventSource) !== \"undefined\") {\n" +
                   "            var source = new EventSource(\"/es\"); // 建立EventSource连接\n" +
                   "            source.onopen = function () { // 连接建立成功时触发\n" +
                   "                document.getElementById(\"info\").innerHTML += \"EventSource连接成功!\" + \"<br>\";\n" +
                   "            };\n" +
                   "            source.onmessage = function (event) { // 收到服务器数据时触发\n" +
                   "                document.getElementById(\"info\").innerHTML += event.data + \"<br>\";\n" +
                   "            };\n" +
                   "            source.onerror = function () { // 发生错误时触发\n" +
                   "                document.getElementById(\"info\").innerHTML += \"通讯发送错误!\" + \"<br>\";\n" +
                   "            };\n" +
                   "        }\n" +
                   "        else {\n" +
                   "            document.getElementById(\"info\").innerHTML = \"浏览器不支持 EventSource!\";\n" +
                   "        }\n" +
                   "    </script>\n" +
                   "</body>\n" +
                   "</html>\n";

AsyncWebServer server(80); // 声明WebServer对象

AsyncEventSource events("/es"); // EventSource对象,url为/es; 注意EventSource和Http是共用url的

// EventSource事件回调函数
void onEventHandle(AsyncEventSourceClient *client)
{
  Serial.printf("Client reconnected! Last message ID that it gat is: %u\n", client->lastId());
  // 向客户端发送hello!
  // events.count()为已经结客户端数,这里用作给客户端的id号
  // 1000表示告诉客户端如果连接断开则再1000毫秒后尝试重新连接
  client->send("hello!", NULL, events.count(), 1000);
}

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

  WiFi.mode(WIFI_STA);
  WiFi.setSleep(false);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected");
  Serial.print("IP Address:");
  Serial.println(WiFi.localIP());

  events.onConnect(onEventHandle); // 绑定当有客户端连接时的回调函数
  server.addHandler(&events);      // 将EventSource添加到服务器中

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { //注册链接"/lambda"与对应回调函数(匿名函数形式声明)
    request->send(200, "text/html", indexhtml);                 //向客户端发送响应和内容
  });

  server.begin(); //启动服务器

  Serial.println("Web server started");
}

void loop()
{
  delay(2000);
  events.send("lalala~~~"); // 向所有已连接的客户端推送消息 // 也可以用events.send("lalala~~~", NULL, events.count(), 1000);
}

在这里插入图片描述
上面就是一个使用EventSource进行通讯的例子,所有的关键步骤都在上面代码中写了注释。可以看到使用EventSource功能服务器可以主动向客户端推送数据。

更多说明

EventSource相比WebSocket简单很多,在完成基本的初始化工作后就只有一个向全体客户端发送消息的功能:
void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0);
另外AsyncEventSource对象还有 void close();size_t count() const; 等少数几个不常用的方法。

在AsyncEventSource对象的onConnect事件回调函数中我们也可以用下面的方法向触发该事件的客户端发送消息:
client->write(const char * message, size_t len);
client->send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0);

总结

ESPAsyncWebServer的WebSocket和EventSource主要就是上面这些内容,更多内容可以查看项目官方的文档和例程,或者我的其他ESPAsyncWebServer的文章:
ESPAsyncWebServer项目地址:https://github.com/me-no-dev/ESPAsyncWebServer
《Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:快速入门》
《Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:事件处理绑定》
《Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:请求与响应》
《Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:静态文件和模板引擎》
《Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:WebSocket和EventSource》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:WebSocket和EventSource 的相关文章

  • android BluetoothChat 使用来自另一个类的发送接收方法

    您好 我使用 BluetoothChat 示例来与 arduino 进行通信 到目前为止 一切正常 现在我想访问 sendMessage 方法 以便能够不从主类发送数据 而是从我创建的另一个类发送数据 这是BluetoothChat jav
  • Arduino F()宏的实现

    我试图了解 Arduino 中的 F 宏实际上对 PGMEM 和 RAM 做了什么以及运行时的影响是什么 有人可以指出定义这个宏的文件吗 这可能是旧版本 但定义它的一个地方是Wstring h as in here http andybro
  • 在 Android 上将 USB 波特率从 9600 更改为 115200

    我有一个 Arduino 它以 115200 波特率串行发送数据 有一个应用程序以 9600 波特率从 Arduino 接收数据 代码是 Arduino USB serial converter setup Set control line
  • 蓝牙 HC-05 发送错误 1F 仅适用于 INQ 命令

    我的新蓝牙 HC 05 模块有问题 在 AT 模式下 它可以与我需要的所有命令完美配合 除了 INQ 我已经尝试事先发送一大堆其他命令 AT INIT OK AT ORGL OK AT ROLE 1 OK AT CLASS 0 OK 他们都
  • 如何在 Arduino 上比较 __FlashStringHelper* 和 char*?

    我有一个将文本行输出到串行的板 我需要将这些文本行与我所知道的文本进行比较 本质上 我想做strcmp thestring F knownstring 但是似乎没有一个采用 FlashStringHelper 类型的 strcmp 版本 有
  • 如何将值从 Arduino 发送到 Python,然后使用该值

    我正在构建一个使用 Python 进行远程控制的机器人 通过简单的 GUI 通过互联网发送控制消息 我的部分代码 GUI 和控制系统 运行得很好 但我陷入了困境 我正在尝试使用视差平传感器来获取与物体的距离信息Arduino Mega ht
  • 经典蓝牙 (2.1) 设备可实现的最小数据包延迟是多少?

    我正在使用 RN42 http www microchip com wwwproducts en RN42 http www microchip com wwwproducts en RN42 蓝牙模块以 115200 波特率 UART S
  • Android BLE 扫描与 UUID 过滤器列表混淆

    我正在 Android 移动设备 A 上执行 UUID 过滤扫描 并且有两个测试用例 一个人在另一台 Android 设备 移动设备 b 上使用名为 BLE Scanner 的应用程序来创建具有两个测试服务 每个服务都有自己唯一的 UUID
  • 静态 uint8_t 数组的输入过程和类型

    我目前正在尝试将 Arduino IDE 中的整数变量转换为静态 uint8 t 数组的值 我在用 include
  • C++ Linux (Ubuntu) 正确写入串行(对于 Arduino)

    我想知道是否有一种标准方法可以与高效的串行设备进行通信 我应该使用标准库吗 如果有 是哪一个 现在我正在摆弄让 LED 根据输入的数字以给定的量亮起 Arduino 代码如下 只是练习一些东西 看我过于简单且低效的测试 include
  • 是否有通用 I2C 命令来查看设备是否仍然存在于总线上?

    是否有通用的 I2C 命令来查看设备在初始化一次后是否仍然存在于总线上 例如 OLED 显示器 我问这个的原因是为了避免主程序由于库代码中存在无限循环而冻结 当设备断开连接时 例如 Wire 库 在 MCU 启动时 我想检查设备是否可用 并
  • HM10 ble改变特征值AT命令Arduino

    谁能帮我用AT命令写入特征值 或者如何使用Hm10模块将数据从arduino发送到另一个ble设备 HM10发送AT START后 会通告数据包 并且可以检测服务和特征 但特征值是默认的0x00 如何更改 多次检查数据表 但找不到能够执行相
  • C#读取Arduino

    我正在尝试制作一个从 Arduino 读取传出信号的应用程序 但我无法使其在 C 中工作Windows 窗体 http en wikipedia org wiki Windows Forms 仅在控制台中 我的 C Windows 窗体代码
  • Arduino 上的 Serial 和 Stream 有什么区别,Serial.write 是如何实现的?

    我很难理解串行和流这两个术语之间的区别 串行不是流的一种吗 我对作业有一些我不明白的问题 计算机通过使用 流或串行 读取 彼此发送的数据来确定每个字节的含义 Also Serial write 我也很困惑 它返回一个字节的数据 对吗 一个字
  • SIM900 GSM/GPRS 未获得正确的 AT+CREG?回答

    我使用的是带有 IComsat SIM900 GSM GPRS 扩展板的 Arduino UNO 使用以下教程 Arduino 实时 GPS 追踪器 http www samaria me uk 2011 12 arduino live g
  • 是否可以在 Arduino 上运行 ZeroMQ

    我想知道是否可以通过 ZeroMQ 与 Arduino 进行通信 我想使用 Arduino 来控制一些设备 并希望将大部分应用程序放在计算机上 为此 如果 Arduino 和控制器可以通过 Zeromq 以及 WiFi 或以太网扩展板进行通
  • Arduino C++ 析构函数?

    我知道在Arduino中你不能使用delete 那么什么时候调用 C 类中定义的析构函数呢 同样 如果我想创建一个指向数组的指针 我必须使用malloc and free 当对象被销毁时 析构函数被调用 对于自动 堆栈上 变量 它在离开其作
  • 编译器:如果条件始终为真/假怎么办

    我想到了条件和编译器 我正在为 Arduino 编写一个应用程序 因此我需要该应用程序尽可能快 在我的代码中我有这个 define DEBUG false if DEBUG String pinName pinName Pin pinNam
  • Python串口通信

    我正在开发一个 Arduino 项目 由于内存限制 我将其与 Python 脚本连接起来 在Python方面 我有一个二维矩阵 其中包含各自的x y坐标值 并且在此列表中有26000个坐标对 因此 为了向大家澄清数据结构 pathlist
  • 无法将 minicom 的输出保存到文件中

    当我使用Minicom从串口捕获数据时 我需要将大数据保存到一个文件中 名为minicom cap 但是 如果我按 Ctrl A 和 L 来捕获文件 则失败 没有创建文件 minicom cap之前并不存在 我的下载目录已正确创建 我的操作

随机推荐

  • [2018.10.25]高通QFIL刷机:高通sdm845_la2.0用QFIL软件meta_build和flat_build刷机

    1 代码准备 i amss standard oem 高通源码 ii test device amss standard oem对应的二进制文件 高通已经编译 iii caf 高通源码对应的谷歌源码 2 编译源码 将amss standar
  • 如何解决Ubuntu终端显示exprot: command not foundNo command 'pyenv' found, did you mean: Command 'p7env' from

    前天安装pyenv失败后 每次打开终端都会显示这样的错误提示 开始以为命令历史的问题 去 bashrc的历史记录中删了都没用 最后发现应该是安装的问题 解决如下 首先安装git sudo apt install git 然后克隆pyenv仓
  • 奥特曼系列ol进不去服务器,奥特曼系列OL闪退怎么办?解决方案

    奥特曼系列OL闪退怎么办 解决方案 2016 02 14 作者 说玩小编 来源 说玩网 评论 9条 我要评论 奥特曼系列OL闪退怎么办 在玩奥特曼系列OL的时候 是不是有时候会遇到黑屏或者闪退等种种问题 所以小编在这里为大家提供一些解决这些
  • c++指针的使用

    指针的基本概念 指针是一个变量 其值为另一个变量的地址 即内存位置的直接地址 指针的作用 可以通过指针间接访问内存 内存编号是从0开始记录的 一般用十六进制数字表示 可以利用指针变量保存地址 指针变量定义语法 数据类型 变量名 int ma
  • 华为OD机试 - 字符串分割(二)(Java)

    题目描述 给定一个非空字符串S 其被N个 分隔成N 1的子串 给定正整数K 要求除第一个子串外 其余的子串每K个字符组成新的子串 并用 分隔 对于新组成的每一个子串 如果它含有的小写字母比大写字母多 则将这个子串的所有大写字母转换为小写字母
  • LeetCode:用队列实现栈(纯C语言)

    题目链接 225 用队列实现栈 力扣 Leetcode 代码 CV复制黏贴 老套路二话不说 先上代码 typedef int QDataType typedef struct QueueNode struct QueueNode next
  • 找回 macOS 10.12 Sierra 安全性与隐私的设置中

    2019独角兽企业重金招聘Python工程师标准 gt gt gt is damaged and can t be opened You should move it to the Trash 当你出现上述报错时 可以参照下面做法 不少用户
  • Keil或MDK编译报错error: L6050U:

    文章目录 摘要 安装步骤 问题描述 使用软件 下载安装包 解决方案 注意事项 总结 思考 更新日志 摘要 硬件环境 无特殊要求 软件环境 Win10 安装步骤 问题描述 MDK5 报错信息 error L6050U The code siz
  • Linux修改只读文件权限

    我们在修改一些配置文件时经常会遇到文件是只读的 修改之后无法保存修改的问题 我们可以使用 chmod 命令来修改文件 夹 属性 sudo chmod 777 file name 所有用户对这个文件 夹 都有读写权限 sudo chmod 6
  • 2020DCIC智慧海洋建设算法赛学习03-特征工程

    序 特征工程往往是算法比赛中最至关重要的一环 一个好的特征工程能够让你的分数有大幅的提升 而如何做好特征工程 从哪些方面入手构建特征就需要经验积累和学习TOP选手的优秀方案 通过学习TOP选手开源代码的特征工程部分 我们可以发现 对于智慧海
  • 【JAVA】递归与迭代:选择正确的方法来解决问题

    文章目录 递归概念 代码示例 计算阶乘 斐波那契数列 遍历文件系统目录 总结 递归概念 递归是一种方法或算法 在该方法中 函数通过调用自身来解决问题 在递归中 问题被划分为更小的同类子问题 并不断地递归调用函数来解决这些子问题 直到达到终止
  • 探究HTTP常见请求头:从基础到进阶

    探究HTTP常见请求头 从基础到进阶 文章目录 探究HTTP常见请求头 从基础到进阶 1 介绍 什么是HTTP请求头 请求头的作用 2 常见请求头详解 User Agent Accept Language Referer Content T
  • 学习SpringMvc第三战-利用SpringMvc实现CRUD

    目录 一 前期环境搭建 1 替换pom xml的内容 2 导入配置文件 小编上传资源 3 修改xml文件 4 点击创建自动生成代码 5 写一个类用于处理页面跳转 二 正式启动SpringMVC的CRUD 1 建立接口 调用自动生成的接口 2
  • AB测试中如何给样本分组?

    目录 什么是AB测试 什么叫样本相似 为什么要样本相似 怎么实现样本相似 随机化 Randomization 再随机化 Rerandomization 协方差适应随机化 Covariance Adaptive Randomization 更
  • 虚拟串口工具_com0com

    因为这年头 都 2012 年了 应该没什么人有在用 Serial port 串行端口 串口 说 Serial port 大家可能想不起来 但说 COM port 大家应该就知道是什么一回事了吧 就是那个从前在计算机后方一定有的 DB9 插头
  • C++11与最小垃圾回收

    C 11新标准为了做到最小的垃圾回收支持 首先对 安全 的指针进行了定义 安全派生的指针是指向由new分配的对象或其子对象的指针 安全派生指针的操作包括 1 在解引用基础上的引用 比如 p 2 定义明确的指针操作 比如p 1 3 定义明确的
  • oracle的stored outline的创建与维护

    author skate time 2011 09 17 执行计划的稳定 如何确定哪些sql的执行计划不稳定 如何固定执行计划 执行计划直接影响app的性能 有的时候执行计划固定是很有用的 有很多因素影响执行计划的不稳定 像optimize
  • Evaluating Fuzz Testing

    1 介绍 信息量太大回头再写 一天后更新 不想写了差不多就下面这些内容吧 2 背景 2 1 fuzzing流程 fuzzing的核心算法 initSeedCorpus 初始化新的输入 isDone 决定fuzzing是否停止 choose
  • 一个程序来比较cuda/c在GPU/CPU的运行效率

    在网上看了一个比较GPU和CPU执行矩阵运算效率的帖子 亲自跑了一下 这是一个CUDA语言程序 请保存为 文件名 cu 我的主机配置如下 CPU G2030 内存8GB 显卡 GTX750ti 代码如下所示 include cuda run
  • Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:WebSocket和EventSource

    文章目录 目的 WebSocket 使用方法 使用演示 更多说明 EventSource 使用方法 使用演示 更多说明 总结 目的 WebSocket和EventSource是HTML5开始提供的功能 WebSocket可以在单个TCP连接