RT-Thread论坛
直播中

卞轮辉

9年用户 1170经验值
私信 关注
[问答]

esp8266 udp server 端口监听错误的原因?

1、使用esp8266 at组件+sal socket实现使用udpserver_sample.c demo代码 udp server,通信失败
2、跟踪代码发现 packegs 里面

  • static int esp8266_socket_connect(struct at_socket *socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)


这个接口封装的at指令,需要server的port,并且 AT+CIPSTART入参需要 udp remote_port和local_port ,但实际传入的port并非初始化sokcet的bind的local_port,而是只有remote_port
3、代码分析

  • int at_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
  • {
  •     ...
  •      if (from && sock->type == AT_SOCKET_UDP && sock->state == AT_SOCKET_OPEN)
  •     {
  •         ip_addr_t remote_addr;
  •         uint16_t remote_port = 0;
  •         char ipstr[16] = { 0 };

  •         socketaddr_to_ipaddr_port(from, &remote_addr, &remote_port);
  •         ipaddr_to_ipstr(from, ipstr);

  •         if (sock->ops->at_connect(sock, ipstr, remote_port, sock->type, RT_FALSE) < 0)
  •         {
  •             result = -1;
  •             goto __exit;
  •         }
  •         sock->state = AT_SOCKET_CONNECT;
  •     }
  •     ...
  • }


sock->ops->at_connect 传入port是remote_port,并非bind local port
4、修改esp8266 packges at 命令封装

  • if (at_obj_exec_cmd(device->client, resp,
  •                                 "AT+CIPSTART=%d,"UDP","%s",%d,%d", device_socket, ip,port, port) < 0)


修改at_socket中 at_connect 入参,把remote_port 换成sock->listen.port

  • if (sock->ops->at_connect(sock, ipstr, sock->listen.port, sock->type, RT_FALSE) < 0)




回帖(1)

笑过就走

2025-10-9 17:33:41

根据您的描述,问题核心在于ESP8266 AT组件的UDP服务器实现中,本地端口(local_port)未正确绑定。以下是具体原因分析和解决方案:


问题原因分析




  1. 参数传递错误



    • esp8266_socket_connect() 函数被调用时,传入的 port 参数是 远程端口remote_port),而非绑定的本地端口(local_port)。

    • 正确的 AT+CIPSTART 指令需要 明确指定本地端口(用于监听),但当前实现未传递绑定的本地端口值。




  2. UDP服务器逻辑缺陷



    • UDP服务器必须绑定固定本地端口以监听数据包,但当前代码在连接阶段(connect)使用了远程端口而非绑定的本地端口。

    • bind() 操作保存了本地端口,但在后续 AT+CIPSTART 调用中未使用该值。




  3. AT指令格式不符



    • ESP8266 UDP服务器要求的AT指令格式为:
      AT+CIPSTART=,"UDP","",,

      其中 local_port 是监听端口,但当前实现未正确填充该字段。







解决方案


需修改 esp8266_socket_connect() 函数,确保绑定本地端口被传递到 AT+CIPSTART 指令。以下是具体步骤:


1. 修改结构体保存本地端口


at_socket 结构体中添加字段存储绑定的本地端口:


struct at_socket {
    int socket;
    int type;
    int state;
    int recv_timeout;
    int local_port; // 新增本地端口字段
};

2. bind() 操作中记录端口


在绑定函数中保存本地端口到结构体:


static int esp8266_socket_bind(struct at_socket *socket, const struct sockaddr *name, socklen_t namelen)
{
    struct sockaddr_in *addr = (struct sockaddr_in *)name;
    socket->local_port = ntohs(addr->sin_port); // 保存端口
    return 0;
}

3. 修改 esp8266_socket_connect() 函数


在连接逻辑中使用绑定的本地端口:


static int esp8266_socket_connect(struct at_socket *socket, char *ip, int32_t port, enum at_socket_type type, rt_bool_t is_client)
{
    char recv_ip[16] = {0};
    int remote_port = port;

    // UDP服务器逻辑:使用绑定的本地端口
    if (type == AT_SOCKET_TYPE_UDP && !is_client)
    {
        // 格式: AT+CIPSTART=,"UDP","",,
        at_send_cmd("AT+CIPSTART=%d,"UDP","%s",%d,%d",
                    socket->socket,
                    ip ? ip : "0",
                    remote_port,
                    socket->local_port); // 关键:传入绑定的本地端口
    }
    // ... 其他类型处理
}

4. 正确初始化UDP服务器


确保在创建UDP服务器时调用 bind() 并设置 is_client = RT_FALSE


// 创建UDP Socket
int sock = socket(AF_INET, SOCK_DGRAM, 0);

// 绑定本地端口
struct sockaddr_in local_addr;
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(LOCAL_PORT); // 服务器监听端口
bind(sock, (struct sockaddr*)&local_addr, sizeof(local_addr));

// 连接配置(此时is_client设为RT_FALSE)
struct sockaddr_in remote_addr;
memset(&remote_addr, 0, sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr("0"); // 任意远程IP
remote_addr.sin_port = htons(0); // 任意远程端口
connect(sock, (struct sockaddr*)&remote_addr, sizeof(remote_addr)); // 触发AT+CIPSTART



关键修复点总结
































步骤 修改内容 目的
1 struct at_socket 添加 local_port 存储绑定的本地端口
2 bind() 中保存端口到结构体 记录监听端口值
3 修改 AT+CIPSTART 填入 local_port 确保AT指令使用正确端口
4 连接时设置 is_client = RT_FALSE 标识服务器模式


注意:ESP8266作为UDP服务器时,AT+CIPSTART 必须明确指定 local_port,且需在 bind() 后调用 connect() 触发连接建立。远程IP/端口可设为 0 表示接收任意源地址数据包。



经此修改后,ESP8266将正确监听指定本地端口,实现UDP服务器功能。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分