feat: mpack + continus stream

This commit is contained in:
pictures2333 2025-12-31 15:55:12 +08:00
parent 0f80116be2
commit ea95b056cc
5 changed files with 202 additions and 120 deletions

View file

@ -55,17 +55,10 @@ extern "C" int command_push_image() {
} }
} }
extern "C" int tcp_client_callback(char *buf, size_t len) { extern "C" int tcp_client_callback(request_t *req) {
for (size_t i = 0; i < len; i++) { printf("cmd -> %s\n", req->command);
printf("%02x ", buf[i]); printf("index -> %llu\n", req->index);
} printf("data_len -> %u\n", req->data_len);
printf("\n");
request_t *req = client_parse_data(buf, len);
if (!req) { // error -> invalid data
return -2;
}
// execute command // execute command
if (strcmp(req->command, "ping") == 0) if (strcmp(req->command, "ping") == 0)
{ {

View file

@ -13,18 +13,18 @@
// change these // change these
static const uint8_t MESH_ID[6] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x76 }; static const uint8_t MESH_ID[6] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x76 };
#define CONFIG_MESH_ROUTER_SSID "FBK_the_cutest_fox" //#define CONFIG_MESH_ROUTER_SSID "FBK_the_cutest_fox"
#define CONFIG_MESH_ROUTER_PASSWD "zsfv3210" //#define CONFIG_MESH_ROUTER_PASSWD "zsfv3210"
//#define CONFIG_MESH_ROUTER_SSID "testesp" #define CONFIG_MESH_ROUTER_SSID "testesp"
//#define CONFIG_MESH_ROUTER_PASSWD "RABCRABC" #define CONFIG_MESH_ROUTER_PASSWD "RABCRABC"
#define CONFIG_MESH_AP_AUTHMODE WIFI_AUTH_WPA2_PSK #define CONFIG_MESH_AP_AUTHMODE WIFI_AUTH_WPA2_PSK
#define CONFIG_MESH_AP_PASSWD "RASRASRAS" #define CONFIG_MESH_AP_PASSWD "RASRASRAS"
#define CONFIG_MESH_AP_CONNECTIONS 6 // number of nodes #define CONFIG_MESH_AP_CONNECTIONS 6 // number of nodes
#define CONFIG_MESH_NON_MESH_AP_CONNECTIONS 0 // number of non-node devices #define CONFIG_MESH_NON_MESH_AP_CONNECTIONS 0 // number of non-node devices
#define CONFIG_TCP_ROOT 0 #define CONFIG_TCP_ROOT 0
//#define CONFIG_TCP_SERVER_IP "172.16.0.1" #define CONFIG_TCP_SERVER_IP "172.16.0.1"
#define CONFIG_TCP_SERVER_IP "10.189.34.172" //#define CONFIG_TCP_SERVER_IP "10.189.34.172"
#define CONFIG_TCP_SERVER_PORT "3030" #define CONFIG_TCP_SERVER_PORT "3030"
#define CONFIG_TCP_RXBUFFER_SIZE 4096 // tcp raw data max size #define CONFIG_TCP_RXBUFFER_SIZE 4096 // tcp raw data max size
#define CONFIG_IMAGE_BUF_SLICE_SIZE 2048 // map["data"] max size #define CONFIG_IMAGE_BUF_SLICE_SIZE 2048 // map["data"] max size
@ -51,7 +51,7 @@ typedef struct request_t {
#if CONFIG_TCP_ROOT == 1 #if CONFIG_TCP_ROOT == 1
int tcp_server_callback(const char *TAG, int sock); int tcp_server_callback(const char *TAG, int sock);
#else #else
int tcp_client_callback(char *buf, size_t len); int tcp_client_callback(request_t *req);
#endif #endif
request_t *client_parse_data(char *buf, size_t len); request_t *client_parse_data(char *buf, size_t len);

View file

@ -18,6 +18,7 @@
#include "nvs_flash.h" #include "nvs_flash.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "mpack.h"
#include "main.h" #include "main.h"
#include "mesh_netif.h" #include "mesh_netif.h"
@ -298,6 +299,20 @@ void start_tcp_server(void)
#else #else
static const char *TAG = "nonblocking-socket-client"; static const char *TAG = "nonblocking-socket-client";
size_t mp_fill(mpack_tree_t *reader, char *buffer, size_t count) {
int sock = (int)reader->context;
ESP_LOGI(TAG, "expect %lu bytes", count);
ssize_t r = recv(sock, buffer, count, 0);
ESP_LOGI(TAG, "received %ld bytes", r);
if (r <= 0) {
mpack_tree_flag_error(reader, mpack_error_io);
return 0;
}
return r;
}
// tcp client // tcp client
static void tcp_client_task(void *pvParameters) static void tcp_client_task(void *pvParameters)
{ {
@ -323,87 +338,114 @@ static void tcp_client_task(void *pvParameters)
ESP_LOGI(TAG, "Socket created, connecting to %s:%s", CONFIG_TCP_SERVER_IP, CONFIG_TCP_SERVER_PORT); ESP_LOGI(TAG, "Socket created, connecting to %s:%s", CONFIG_TCP_SERVER_IP, CONFIG_TCP_SERVER_PORT);
// Marking the socket as non-blocking // Marking the socket as non-blocking
int flags = fcntl(sock, F_GETFL); //int flags = fcntl(sock, F_GETFL);
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) { //if (fcntl(sock, F_SETFL, flags) == -1) {
log_socket_error(TAG, sock, errno, "Unable to set socket non blocking"); // log_socket_error(TAG, sock, errno, "Unable to set socket non blocking");
} //}
if (connect(sock, address_info->ai_addr, address_info->ai_addrlen) != 0) { if (connect(sock, address_info->ai_addr, address_info->ai_addrlen) != 0) {
if (errno == EINPROGRESS) { ESP_LOGE(TAG, "Failed to connect server");
ESP_LOGD(TAG, "connection in progress");
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(sock, &fdset);
// Connection in progress -> have to wait until the connecting socket is marked as writable, i.e. connection completes
res = select(sock+1, NULL, &fdset, NULL, NULL);
if (res < 0) {
log_socket_error(TAG, sock, errno, "Error during connection: select for socket to be writable");
goto error;
} else if (res == 0) {
log_socket_error(TAG, sock, errno, "Connection timeout: select for socket to be writable");
goto error;
} else {
int sockerr;
socklen_t len = (socklen_t)sizeof(int);
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
log_socket_error(TAG, sock, errno, "Error when getting socket error using getsockopt()");
goto error;
}
if (sockerr) {
log_socket_error(TAG, sock, sockerr, "Connection error");
goto error;
}
}
} else {
log_socket_error(TAG, sock, errno, "Socket is unable to connect");
goto error;
}
} }
//if (connect(sock, address_info->ai_addr, address_info->ai_addrlen) != 0) {
// if (errno == EINPROGRESS) {
// ESP_LOGD(TAG, "connection in progress");
// fd_set fdset;
// FD_ZERO(&fdset);
// FD_SET(sock, &fdset);
//
// // Connection in progress -> have to wait until the connecting socket is marked as writable, i.e. connection completes
// res = select(sock+1, NULL, &fdset, NULL, NULL);
// if (res < 0) {
// log_socket_error(TAG, sock, errno, "Error during connection: select for socket to be writable");
// goto error;
// } else if (res == 0) {
// log_socket_error(TAG, sock, errno, "Connection timeout: select for socket to be writable");
// goto error;
// } else {
// int sockerr;
// socklen_t len = (socklen_t)sizeof(int);
//
// if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
// log_socket_error(TAG, sock, errno, "Error when getting socket error using getsockopt()");
// goto error;
// }
// if (sockerr) {
// log_socket_error(TAG, sock, sockerr, "Connection error");
// goto error;
// }
// }
// } else {
// log_socket_error(TAG, sock, errno, "Socket is unable to connect");
// goto error;
// }
//}
ESP_LOGI(TAG, "Connected to %s:%s", CONFIG_TCP_SERVER_IP, CONFIG_TCP_SERVER_PORT); ESP_LOGI(TAG, "Connected to %s:%s", CONFIG_TCP_SERVER_IP, CONFIG_TCP_SERVER_PORT);
// Keep receiving message
do {
// receive
int len = 0;
memset(rx_buffer, 0, sizeof(rx_buffer));
do {
len = try_receive(TAG, sock, rx_buffer, sizeof(rx_buffer));
if (len < 0) {
ESP_LOGE(TAG, "Error occurred during try_receive");
goto error;
}
vTaskDelay(pdMS_TO_TICKS(YIELD_TO_ALL_MS));
} while (len == 0);
ESP_LOGI(TAG, "Received message (len=%d)", len);
// execute command // mpack
char tx_buffer[128] = {0}; mpack_tree_t tree;
int result = tcp_client_callback(rx_buffer, len); mpack_tree_init_stream(&tree, mp_fill, (void *)sock, CONFIG_IMAGE_BUF_SIZE, 30);
switch (result) {
case 0: while (true) {
strcpy(tx_buffer, "ok\n"); mpack_tree_parse(&tree);
break; if (mpack_tree_error(&tree) != mpack_ok) {
case -2: ESP_LOGE(TAG, "mperror: %d\n", mpack_tree_error(&tree));
strcpy(tx_buffer, "invalid request\n"); break;
break; }
case -3:
strcpy(tx_buffer, "locked\n"); // parse
break; mpack_node_t root = mpack_tree_root(&tree);
default: char *cmd = mpack_node_cstr_alloc(mpack_node_map_cstr(root, "command"), 30);
strcpy(tx_buffer, "unknown error\n");
break; size_t index = 0;
} size_t data_size = 0;
char *data = NULL;
if (strcmp(cmd, "update_image") == 0) {
index = mpack_node_u64(mpack_node_map_cstr(root, "index"));
data_size = mpack_node_data_len(mpack_node_map_cstr(root, "data"));
data = (char *)mpack_node_data(mpack_node_map_cstr(root, "data"));
}
// callback
request_t req;
memset(&req, 0, sizeof(req));
req.command = cmd;
req.index = index;
req.data = data;
req.data_len = data_size;
int result = tcp_client_callback(&req);
char tx_buffer[128] = {0};
switch (result) {
case 0:
strcpy(tx_buffer, "ok\n");
break;
case -2:
strcpy(tx_buffer, "invalid request\n");
break;
case -3:
strcpy(tx_buffer, "locked\n");
break;
default:
strcpy(tx_buffer, "unknown error\n");
break;
}
// send result
int send_len = socket_send(TAG, sock, tx_buffer, strlen(tx_buffer));
if (send_len < 0) {
ESP_LOGE(TAG, "Error occurred during socket_send");
goto error;
}
ESP_LOGI(TAG, "Written: %.*s", send_len, tx_buffer);
// end
free(cmd);
cmd=NULL;
}
// send result
len = socket_send(TAG, sock, tx_buffer, strlen(tx_buffer));
if (len < 0) {
ESP_LOGE(TAG, "Error occurred during socket_send");
goto error;
}
ESP_LOGI(TAG, "Written: %.*s", len, tx_buffer);
} while (true);
error: error:
if (sock != INVALID_SOCK) { if (sock != INVALID_SOCK) {

75
tcp_client2.py Normal file
View file

@ -0,0 +1,75 @@
from typing import Dict, Any
import socket
import msgpack
import tcp_client_image
HOST = "0.0.0.0"
PORT = 3030
def send_request(client_socket:socket.socket, data:Dict[str, Any]):
try:
message:bytes = msgpack.packb(data)
client_socket.sendall(message)
rx = client_socket.recv(1024)
if data:
print(f"Received message: {rx.decode('utf-8').strip()}")
else:
print("Connection closed")
return
except ConnectionResetError:
print("Connection reset")
def image(s:socket.socket):
image = b""
try:
choice = int(input("image > "))
if choice == 1:
image = tcp_client_image.image1
elif choice == 2:
image = tcp_client_image.image2
else:
raise ValueError
except:
print("invalid choice")
return
chunk_size = 2048
for i in range(0, len(image), chunk_size):
data = {
"command": "update_image",
"index": i,
"data": bytes(image[i:i+chunk_size])
}
send_request(s, data)
send_request(s, {"command":"push_image"})
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen(5)
print("listening...")
conn, addr = s.accept() # 阻塞
with conn:
while True:
print("Command:")
print("(1) update + push image")
print("(2) ping")
print("(3) invalid request")
print("(4) exit")
choice:int = int(input("> "))
data = {}
if choice == 1:
image(conn)
elif choice == 2:
send_request(conn, {"command":"ping"})
elif choice == 3:
send_request(conn, {"command":"invalid_command"})
else:
break

View file

@ -1,28 +0,0 @@
import asyncio
import signal
async def handle_client(reader, writer):
try:
while True:
#data = await reader.readline()
#if not data:
# break
#
#msg = data.decode().strip()
#writer.write(f"echo: {msg}\n".encode())
await writer.drain()
except Exception as e:
print("error:", e)
finally:
writer.close()
await writer.wait_closed()
async def main():
server = await asyncio.start_server(
handle_client, host="0.0.0.0", port=3030
)
async with server:
await server.serve_forever()
asyncio.run(main())