警告

This document is not updated for ESP32C61 yet, so some of the content may not be correct.

This warning was automatically inserted due to the source file being in the add_warnings_pages list.

# ICMP 回显

[English]

## 概述

网际控制报文协议 (ICMP) 通常用于诊断或控制目的，或响应 IP 操作中的错误。常用的网络工具 `ping` 的应答，即 `Echo Reply`，就是基于类型字段值为 0 的 ICMP 数据包实现的。

在 ping 会话中，首先由源主机发出请求包 (ICMP echo request)，然后等待应答包 (ICMP echo reply)，等待具有超时限制。通过这一过程，还能测量出信息的往返用时。收到有效的应答包后，源主机会生成 IP 链路层的统计数据（如失包率、运行时间等）。

IoT 设备通常需要检查远程服务器是否可用。如果服务器离线，设备应向用户发出警告。通过创建 ping 会话，定期发送或解析 ICMP echo 数据包，就能实现这一功能。

为简化这一过程方便用户操作，ESP-IDF 提供了一些好用的 API。

### 创建 ping 会话

要创建 ping 会话，首先需填写 `esp_ping_config_t`，指定目标芯片 IP 地址、间隔时间等配置。此外，还可以通过 `esp_ping_callbacks_t` 注册回调函数。

创建 ping 会话并注册回调函数示例：

    static void test_on_ping_success(esp_ping_handle_t hdl, void *args)
    {
        // optionally, get callback arguments
        // const char* str = (const char*) args;
        // printf("%s\r\n", str); // "foo"
        uint8_t ttl;
        uint16_t seqno;
        uint32_t elapsed_time, recv_len;
        ip_addr_t target_addr;
        esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
        esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
        esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
        esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
        esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
        printf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n",
               recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
    }

    static void test_on_ping_timeout(esp_ping_handle_t hdl, void *args)
    {
        uint16_t seqno;
        ip_addr_t target_addr;
        esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
        esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
        printf("From %s icmp_seq=%d timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno);
    }

    static void test_on_ping_end(esp_ping_handle_t hdl, void *args)
    {
        uint32_t transmitted;
        uint32_t received;
        uint32_t total_time_ms;

        esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
        esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
        esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
        printf("%d packets transmitted, %d received, time %dms\n", transmitted, received, total_time_ms);
    }

    void initialize_ping()
    {
        /* convert URL to IP address */
        ip_addr_t target_addr;
        struct addrinfo hint;
        struct addrinfo *res = NULL;
        memset(&hint, 0, sizeof(hint));
        memset(&target_addr, 0, sizeof(target_addr));
        getaddrinfo("www.espressif.com", NULL, &hint, &res);
        struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
        inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
        freeaddrinfo(res);

        esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG();
        ping_config.target_addr = target_addr;          // target IP address
        ping_config.count = ESP_PING_COUNT_INFINITE;    // ping in infinite mode, esp_ping_stop can stop it

        /* set callback functions */
        esp_ping_callbacks_t cbs;
        cbs.on_ping_success = test_on_ping_success;
        cbs.on_ping_timeout = test_on_ping_timeout;
        cbs.on_ping_end = test_on_ping_end;
        cbs.cb_args = "foo";  // arguments that will feed to all callback functions, can be NULL
        cbs.cb_args = eth_event_group;

        esp_ping_handle_t ping;
        esp_ping_new_session(&ping_config, &cbs, &ping);
    }

### 启动和停止 ping 会话

使用 `esp_ping_new_session` 返回的句柄可以启动或停止 ping 会话。注意，ping 会话在创建后不会自动启动。如果 ping 会话停止后重启，ICMP 数据包的序列号会归零重新计数。

### 删除 ping 会话

如果不再使用 ping 会话，可用 `esp_ping_delete_session` 将其删除。在删除 ping 会话时，确保该会话已处于停止状态（即已调用了 `esp_ping_stop` ，或该会话已完成所有步骤）。

### 获取运行时间数据

在回调函数中调用 `esp_ping_get_profile`，可获取 ping 会话的不同运行时间数据，如上文代码示例所示。

## 应用示例

- protocols/icmp_echo 演示了如何实现一个简单的 ping 命令行工具，使用 ICMP 回显请求数据包测试远程主机在 IP 网络上的可达性。

- protocols/icmp/pmtu_probe 演示了如何使用 ICMP 回显请求探测路径 MTU，并通过 `esp_netif_set_mtu()` 将探测结果应用到活动接口。

## API 参考

### Header File

- components/lwip/include/apps/ping/ping_sock.h

- This header file can be included with:

  >     #include "ping/ping_sock.h"

- This header file is a part of the API provided by the `lwip` component. To declare that your component depends on `lwip`, add the following to your CMakeLists.txt:

  >     REQUIRES lwip

  > or

  >     PRIV_REQUIRES lwip

### Functions

esp_err_t esp_ping_new_session(const esp_ping_config_t *config, const esp_ping_callbacks_t *cbs, esp_ping_handle_t *hdl_out)

  Create a ping session.

  参数:

    - config -- ping configuration

    - cbs -- a bunch of callback functions invoked by internal ping task

    - hdl_out -- handle of ping session

  返回:

    - ESP_ERR_INVALID_ARG: invalid parameters (e.g. configuration is null, etc)

    - ESP_ERR_NO_MEM: out of memory

    - ESP_FAIL: other internal error (e.g. socket error)

    - ESP_OK: create ping session successfully, user can take the ping handle to do follow-on jobs

esp_err_t esp_ping_delete_session(esp_ping_handle_t hdl)

  Delete a ping session.

  参数:

    hdl -- handle of ping session

  返回:

    - ESP_ERR_INVALID_ARG: invalid parameters (e.g. ping handle is null, etc)

    - ESP_OK: delete ping session successfully

esp_err_t esp_ping_start(esp_ping_handle_t hdl)

  Start the ping session.

  参数:

    hdl -- handle of ping session

  返回:

    - ESP_ERR_INVALID_ARG: invalid parameters (e.g. ping handle is null, etc)

    - ESP_OK: start ping session successfully

esp_err_t esp_ping_stop(esp_ping_handle_t hdl)

  Stop the ping session.

  参数:

    hdl -- handle of ping session

  返回:

    - ESP_ERR_INVALID_ARG: invalid parameters (e.g. ping handle is null, etc)

    - ESP_OK: stop ping session successfully

esp_err_t esp_ping_get_profile(esp_ping_handle_t hdl, esp_ping_profile_t profile, void *data, uint32_t size)

  Get runtime profile of ping session.

  参数:

    - hdl -- handle of ping session

    - profile -- type of profile

    - data -- profile data

    - size -- profile data size

  返回:

    - ESP_ERR_INVALID_ARG: invalid parameters (e.g. ping handle is null, etc)

    - ESP_ERR_INVALID_SIZE: the actual profile data size doesn't match the "size" parameter

    - ESP_OK: get profile successfully

### Structures

struct esp_ping_callbacks_t

  Type of "ping" callback functions.

  Public Members

  void *cb_args

    arguments for callback functions

  void (*on_ping_success)(esp_ping_handle_t hdl, void *args)

    Invoked by internal ping thread when received ICMP echo reply packet.

  void (*on_ping_timeout)(esp_ping_handle_t hdl, void *args)

    Invoked by internal ping thread when receive ICMP echo reply packet timeout.

  void (*on_ping_end)(esp_ping_handle_t hdl, void *args)

    Invoked by internal ping thread when a ping session is finished.

struct esp_ping_config_t

  Type of "ping" configuration.

  Public Members

  uint32_t count

    A "ping" session contains count procedures

  uint32_t interval_ms

    Milliseconds between each ping procedure

  uint32_t timeout_ms

    Timeout value (in milliseconds) of each ping procedure

  uint32_t data_size

    Size of the data next to ICMP packet header

  int tos

    Type of Service, a field specified in the IP header

  int ttl

    Time to Live,a field specified in the IP header

  ip_addr_t target_addr

    Target IP address, either IPv4 or IPv6

  uint32_t task_stack_size

    Stack size of internal ping task

  uint32_t task_prio

    Priority of internal ping task

  uint32_t interface

    Netif index, interface=0 means NETIF_NO_INDEX

### Macros

ESP_PING_DEFAULT_CONFIG()

  Default ping configuration.

ESP_PING_COUNT_INFINITE

  Set ping count to zero will ping target infinitely

### Type Definitions

typedef void *esp_ping_handle_t

  Type of "ping" session handle.

### Enumerations

enum esp_ping_profile_t

  Profile of ping session.

  Values:

  enumerator ESP_PING_PROF_SEQNO

    Sequence number of a ping procedure

  enumerator ESP_PING_PROF_TOS

    Type of service of a ping procedure

  enumerator ESP_PING_PROF_TTL

    Time to live of a ping procedure

  enumerator ESP_PING_PROF_REQUEST

    Number of request packets sent out

  enumerator ESP_PING_PROF_REPLY

    Number of reply packets received

  enumerator ESP_PING_PROF_IPADDR

    IP address of replied target

  enumerator ESP_PING_PROF_SIZE

    Size of received packet

  enumerator ESP_PING_PROF_TIMEGAP

    Elapsed time between request and reply packet

  enumerator ESP_PING_PROF_DURATION

    Elapsed time of the whole ping session

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。