【发布时间】:2021-04-16 22:57:49
【问题描述】:
我目前正在对我的 ESP-WROVER-KIT 和我的 PC 之间的 WIFI 连接进行原型设计。我对我的方法和结果有一些疑问。
此原型的目的是使 ESP32 和 PC 之间的网络延迟尽可能低(大约 6-10 毫秒会很棒),并且数据包大小保持 512 字节。目前PC通过以太网电缆连接到WIFI路由器。由于这是我第一次涉足网络,我做了一些研究并得出结论,TCP套接字连接将是一种有据可查的方法,有可能获取数据需要延迟。我使用 ESP32 的 esp-idf 套接字示例和我的 PC 的 Windows 窗体应用程序的在线示例代码作为我的代码库,并进行了一些修改以测量返回时间和发送所需的数据包大小。回程时间的测量是通过添加秒表(Windows 窗体)或向上计时器(ESP32)并测量阻塞调用中发送和接收数据包之间的时间来完成的。
第一个测试将 ESP32 作为服务器作为回显,Windows 窗体作为客户端,发送一个 512 字节的数据包并计算返回所需的时间。本次交易记录的回程时间约为 40-50 毫秒。此值已使用 Wireshark 确认。
ESP32 服务器回显
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#define PORT CONFIG_EXAMPLE_PORT
static const char *TAG = "example";
static void do_retransmit(const int sock)
{
int len;
char rx_buffer[513];
do {
len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if (len < 0) {
ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);
} else if (len == 0) {
ESP_LOGW(TAG, "Connection closed");
} else {
rx_buffer[len] = 0; // Null-terminate whatever is received and treat it like a string
ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer);
// send() can return less bytes than supplied length.
// Walk-around for robust implementation.
int to_write = len;
while (to_write > 0) {
int written = send(sock, rx_buffer + (len - to_write), to_write, 0);
if (written < 0) {
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
}
to_write -= written;
//vTaskDelay(10);
}
}
} while (len > 0);
}
static void tcp_server_task(void *pvParameters)
{
char addr_str[513];
int addr_family = (int)pvParameters;
int ip_protocol = 0;
struct sockaddr_in6 dest_addr;
if (addr_family == AF_INET) {
struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;
dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
dest_addr_ip4->sin_family = AF_INET;
dest_addr_ip4->sin_port = htons(PORT);
ip_protocol = IPPROTO_IP;
} else if (addr_family == AF_INET6) {
bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un));
dest_addr.sin6_family = AF_INET6;
dest_addr.sin6_port = htons(PORT);
ip_protocol = IPPROTO_IPV6;
}
int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (listen_sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
vTaskDelete(NULL);
return;
}
#if defined(CONFIG_EXAMPLE_IPV4) && defined(CONFIG_EXAMPLE_IPV6)
// Note that by default IPV6 binds to both protocols, it is must be disabled
// if both protocols used at the same time (used in CI)
int opt = 1;
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
#endif
ESP_LOGI(TAG, "Socket created");
int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
ESP_LOGE(TAG, "IPPROTO: %d", addr_family);
goto CLEAN_UP;
}
ESP_LOGI(TAG, "Socket bound, port %d", PORT);
err = listen(listen_sock, 1);
if (err != 0) {
ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
goto CLEAN_UP;
}
while (1) {
ESP_LOGI(TAG, "Socket listening");
struct sockaddr_in6 source_addr; // Large enough for both IPv4 or IPv6
uint addr_len = sizeof(source_addr);
int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
break;
}
// Convert ip address to string
if (source_addr.sin6_family == PF_INET) {
inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
} else if (source_addr.sin6_family == PF_INET6) {
inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
}
ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str);
do_retransmit(sock);
shutdown(sock, 0);
close(sock);
}
CLEAN_UP:
close(listen_sock);
vTaskDelete(NULL);
}
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
#ifdef CONFIG_EXAMPLE_IPV4
xTaskCreate(tcp_server_task, "tcp_server", 4096, (void*)AF_INET, 5, NULL);
#endif
#ifdef CONFIG_EXAMPLE_IPV6
xTaskCreate(tcp_server_task, "tcp_server", 4096, (void*)AF_INET6, 5, NULL);
#endif
}
Windows 窗体客户端发送/接收/时间
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.Threading;
public class GetSocket
{
private static Socket ConnectSocket()
{
Socket socket = null;
IPHostEntry hostEntry = null;
// Get host related information.
// Loop through the AddressList to obtain the supported AddressFamily. This is to avoid
// an exception that occurs when the host IP Address is not compatible with the address family
// (typical in the IPv6 case).
IPEndPoint ipe = new IPEndPoint(771860672, 3333);
///IPEndPoint ipe = new IPEndPoint(2046929088, 3333);
/*Socket tempSocket =
new Socket(ipe.AddressFamily, SocketType.Dgram, ProtocolType.Udp);*/
Socket tempSocket =
new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
tempSocket.Connect(ipe);
if(tempSocket.Connected)
{
socket = tempSocket;
}
return socket;
}
// This method requests the home page content for the specified server.
private static string SocketSendReceive(string server, int port)
{
string request = "abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdfeghijhk";
Byte[] bytesSent = Encoding.ASCII.GetBytes(request);
Byte[] bytesReceived = new Byte[512];
string page = "";
// Create a socket connection with the specified server and port.
using (Socket socket = ConnectSocket()) {
if (socket == null)
return ("Connection failed");
socket.NoDelay = true; /*Need to remove for UDP connection*/
int dataLengthReceived = 0;
UInt32[] bytearray = new UInt32[512];
int index = 0;
double[] timearraymili = new double[512];
int timindex = 0;
byte sendCount = 0;
socket.ReceiveTimeout = 0;
Stopwatch stopWatch = new Stopwatch();
TimeSpan ts = stopWatch.Elapsed;
do
{
ts = TimeSpan.Zero;
for(var count = 0; count < bytesSent.Length; count++)
{
bytesSent[count] = (byte)sendCount;
}
stopWatch.Reset();
stopWatch.Start();
socket.Send(bytesSent, bytesSent.Length, 0);
dataLengthReceived = socket.Receive(bytesReceived, bytesReceived.Length, 0);
stopWatch.Stop();
ts = stopWatch.Elapsed;
if(dataLengthReceived == 512)
{
timearraymili[timindex] = ts.TotalMilliseconds;
timindex++;
Debug.WriteLine("Send Count {0} - Latency = {1} ms", sendCount, ts.TotalMilliseconds.ToString("0.000"));
for(var count = 0; count < bytesReceived.Length; count++)
{
if(bytesReceived[count] != sendCount)
{
Debug.WriteLine("Invalid Data Received {0} != {1}", bytesReceived[count], sendCount);
}
}
}
else
{
Debug.WriteLine("bytes received != 512: {0} - elapsed{2}", dataLengthReceived.ToString(), stopWatch.ElapsedMilliseconds);
}
sendCount++;
//Thread.Sleep(100);
}
while (dataLengthReceived > 0);
}
return page;
}
public static void Main(string[] args)
{
string host;
int port = 3333;
if (args.Length == 0)
// If no server name is passed as argument to this program,
// use the current host name as the default.
host = Dns.GetHostName();
else
host = args[0];
string result = SocketSendReceive(host, port);
Console.WriteLine(result);
}
}
第二个测试让 ESP32 作为客户端充当回显,Windows 窗体是服务器,发送一个 512 字节的数据包并计算它返回所需的时间。本次交易记录的回程时间约为 40-50 毫秒。此值已使用 Wireshark 确认。
ESP32 客户端回显
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "addr_from_stdin.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#if defined(CONFIG_EXAMPLE_IPV4)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#elif defined(CONFIG_EXAMPLE_IPV6)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#define HOST_IP_ADDR ""
#endif
#define PORT CONFIG_EXAMPLE_PORT
static const char *TAG = "example";
static void tcp_client_task(void *pvParameters)
{
int len;
char rx_buffer[513];
char host_ip[] = HOST_IP_ADDR;
int addr_family = 0;
int ip_protocol = 0;
while (1) {
#if defined(CONFIG_EXAMPLE_IPV4)
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(PORT);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;
#elif defined(CONFIG_EXAMPLE_IPV6)
struct sockaddr_in6 dest_addr = { 0 };
inet6_aton(host_ip, &dest_addr.sin6_addr);
dest_addr.sin6_family = AF_INET6;
dest_addr.sin6_port = htons(PORT);
dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
addr_family = AF_INET6;
ip_protocol = IPPROTO_IPV6;
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
struct sockaddr_in6 dest_addr = { 0 };
ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_STREAM, &ip_protocol, &addr_family, &dest_addr));
#endif
int sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);
int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Successfully connected");
do {
len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if (len < 0) {
ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);
}
else if (len == 0) {
ESP_LOGW(TAG, "Connection closed");
}
else {
rx_buffer[len] = 0;
ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer);
int to_write = len;
while (to_write > 0) {
int written = send(sock, rx_buffer + (len - to_write), to_write, 0);
if (written < 0) {
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
}
to_write -= written;
}
}
} while (len > 0);
if (sock != -1) {
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(sock, 0);
close(sock);
}
}
vTaskDelete(NULL);
}
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
}
Windows 窗体服务器发送/接收/时间
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Diagnostics;
using System.Threading;
class MyTcpListener
{
public static void Main()
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 3333;
IPAddress localAddr = IPAddress.Parse("192.168.1.199");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
string request = "abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdfeghijhk";
Byte[] bytesSent = Encoding.ASCII.GetBytes(request);
Byte[] bytesReceived = new Byte[512];
int dataLengthReceived = 0;
String dataReceived;
UInt32[] bytearray = new UInt32[512];
double[] timearraymili = new double[512];
int timindex = 0;
byte sendCount = 0;
Stopwatch stopWatch = new Stopwatch();
TimeSpan ts = stopWatch.Elapsed;
// Enter the listening loop.
while (true)
{
Debug.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also use server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Debug.WriteLine("Connected!");
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
do
{
ts = TimeSpan.Zero;
for (var count = 0; count < bytesSent.Length; count++)
{
bytesSent[count] = (byte)sendCount;
}
stopWatch.Reset();
stopWatch.Start();
stream.Write(bytesSent, 0, bytesSent.Length);
stream.Read(bytesReceived, 0, bytesReceived.Length);
stopWatch.Stop();
ts = stopWatch.Elapsed;
dataReceived = System.Text.Encoding.ASCII.GetString(bytesReceived, 0, bytesReceived.Length);
dataLengthReceived = dataReceived.Length;
if (dataLengthReceived == 512)
{
timearraymili[timindex] = ts.TotalMilliseconds;
timindex++;
Debug.WriteLine("Send Count {0} - Latency = {1} ms", sendCount, ts.TotalMilliseconds.ToString("0.000"));
for (var count = 0; count < bytesReceived.Length; count++)
{
if (bytesReceived[count] != sendCount)
{
Debug.WriteLine("Invalid Data Received {0} != {1}", bytesReceived[count], sendCount);
}
}
}
else
{
Debug.WriteLine("bytes received != 512: {0} - elapsed{2}", dataLengthReceived.ToString(), stopWatch.ElapsedMilliseconds);
}
sendCount++;
}
while (dataLengthReceived > 0);
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
}
第三个测试让 ESP32 作为客户端发送一个 512 字节的数据包,并计算它返回所需的时间,Windows 窗体是充当回显的服务器。本次交易记录的回程时间约为 6-10ms(回程时间值在下一个数据包中发送)。在测量从 ESP32 (ESP32-PC-ESP32) 点返回的行程时,使用 Wireshark 确认了该值。但是如果从PC(PC-ESP32-PC)的角度在Wireshark中测量,返回时间大约为40-50ms。
ESP32 客户端服务器发送/接收/时间
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "addr_from_stdin.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "timer_types.h"
#include "timer.h"
#include <esp_app_trace.h>
#if defined(CONFIG_EXAMPLE_IPV4)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#elif defined(CONFIG_EXAMPLE_IPV6)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#define HOST_IP_ADDR ""
#endif
#define PORT CONFIG_EXAMPLE_PORT
static const char *TAG = "example";
char ESP_Tx_512Bytes[512] = "Message from ESP32333 ";
static void tcp_client_task(void *pvParameters)
{
char rx_buffer[513];
char host_ip[] = HOST_IP_ADDR;
int addr_family = 0;
int ip_protocol = 0;
double stopwatchtime;
timer_config_t stopwatch;
stopwatch.divider = 80;
stopwatch.counter_dir = TIMER_COUNT_UP;
stopwatch.alarm_en = TIMER_ALARM_DIS;
timer_init(TIMER_GROUP_0, 0, &stopwatch);
while (1) {
#if defined(CONFIG_EXAMPLE_IPV4)
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(PORT);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;
#elif defined(CONFIG_EXAMPLE_IPV6)
struct sockaddr_in6 dest_addr = { 0 };
inet6_aton(host_ip, &dest_addr.sin6_addr);
dest_addr.sin6_family = AF_INET6;
dest_addr.sin6_port = htons(PORT);
dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
addr_family = AF_INET6;
ip_protocol = IPPROTO_IPV6;
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
struct sockaddr_in6 dest_addr = { 0 };
ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_STREAM, &ip_protocol, &addr_family, &dest_addr));
#endif
int sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);
int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Successfully connected");
while (1) {
timer_set_counter_value(TIMER_GROUP_0, 0, 0);
timer_start(TIMER_GROUP_0, 0);
int err = send(sock, ESP_Tx_512Bytes, strlen(ESP_Tx_512Bytes), 0);
if (err < 0) {
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
break;
}
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
// Error occurred during receiving
if(len < 0) {
ESP_LOGE(TAG, "recv failed: errno %d", errno);
break;
}
// Data received
else {
rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
timer_pause(TIMER_GROUP_0, 0);
timer_get_counter_time_sec(TIMER_GROUP_0, 0, &stopwatchtime);
ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
ESP_LOGI(TAG, "%s", rx_buffer);
ESP_LOGI(TAG, "Latency: %lf seconds", stopwatchtime);
sprintf(ESP_Tx_512Bytes, "Latency: %lf seconds PacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePacketSizePZPZ", stopwatchtime);
}
}
if (sock != -1) {
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(sock, 0);
close(sock);
}
}
vTaskDelete(NULL);
}
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
}
Windows 窗体回显
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
class MyTcpListener
{
public static void Main()
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 3333;
IPAddress localAddr = IPAddress.Parse("192.168.1.199");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[513];
String data = null;
// Enter the listening loop.
while (true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also use server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", data);
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
}
问题: 在测试 3 的情况下,使用wireshark 测量的回程时间是否表明最大的延迟来自通过ESP32 处理数据?还是我误解了数据? 我在阻塞调用中的 Windows 表单应用程序(秒表)和 ESP32(向上计数的计时器)中测试回程时间的方法是否准确? 由于从 PC 到 ESP32 并返回的事务平均返回时间为 40-50 毫秒,因此我应该注意哪些设置或代码优化有助于减少此时间? 如果这是我可以期待的最佳时间,您会推荐任何其他协议来实现更好的回程时间吗? 请注意,我在每种情况下都禁用了 TCP 套接字 (TCP_NODELAY) 上的 Nagle 算法,但这并不影响结果。
感谢您的宝贵时间
【问题讨论】:
-
欢迎来到 Stack Overflow。这个问题太长了。您能否将问题重新格式化如下:问题陈述,您尝试过的内容,您的预期输出,如果有的话,样本数据。请阅读如何问好questions。确保您的问题涵盖以下 3 个要素:1. 问题陈述 2. 您的代码(应该是 Minimal, Reproducible Example 3. 错误消息(最好是完整的 Traceback 以帮助其他人查看和提供反馈)。