当前位置: 首页 > news >正文

ESP32S3 WIFI 实现TCP服务器和静态IP

一、 TCP服务器代码

代码由station_example_main的官方例程修改

/* WiFi station Example

   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 "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 <stdlib.h>
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include <lwip/netdb.h>

/* The examples use WiFi configuration that you can set via project configuration menu

   If you'd rather not, just change the below entries to strings with
   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY  CONFIG_ESP_MAXIMUM_RETRY

#define EXAMPLE_MAX_STA_CONN        4  // 最大客户端连接数
#define PORT                        8080
#define KEEPALIVE_IDLE              5
#define KEEPALIVE_INTERVAL          5
#define KEEPALIVE_COUNT             3

#if CONFIG_ESP_WPA3_SAE_PWE_HUNT_AND_PECK
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HUNT_AND_PECK
#define EXAMPLE_H2E_IDENTIFIER ""
#elif CONFIG_ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HASH_TO_ELEMENT
#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID
#elif CONFIG_ESP_WPA3_SAE_PWE_BOTH
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_BOTH
#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID
#endif
#if CONFIG_ESP_WIFI_AUTH_OPEN
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN
#elif CONFIG_ESP_WIFI_AUTH_WEP
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP
#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK
#endif

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1
#define WIFI_CONNECTED_SUCCESS      BIT2


// 客户端任务参数结构体
typedef struct {
    int socket;
    struct sockaddr_in addr;
} client_params_t;

static const char *TAG = "wifi station";

static int s_retry_num = 0;


static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        } else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_SUCCESS |WIFI_CONNECTED_BIT);
  
    }
}

void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (password len => 8).
             * If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
             * to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to
             * WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.
             */
            .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
            .sae_pwe_h2e = ESP_WIFI_SAE_MODE,
            .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }
}

// 客户端处理任务
void client_task(void *pvParameters)
{
    client_params_t *params = (client_params_t *)pvParameters;
    int sock = params->socket;
    struct sockaddr_in addr = params->addr;
    free(pvParameters); // 释放分配的内存

    char addr_str[128];
    inet_ntoa_r(addr.sin_addr, addr_str, sizeof(addr_str) - 1);
    ESP_LOGI(TAG, "客户端任务启动: IP=%s, 端口=%d", addr_str, ntohs(addr.sin_port));

    char rx_buffer[128];
    char tx_buffer[128];
    
    // 设置keepalive选项
    int keepAlive = 1;
    int keepIdle = KEEPALIVE_IDLE;
    int keepInterval = KEEPALIVE_INTERVAL;
    int keepCount = KEEPALIVE_COUNT;
    
    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int));
    setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int));
    setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int));
    setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int));

    // 设置接收超时
    struct timeval timeout;
    timeout.tv_sec = 10;
    timeout.tv_usec = 0;
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

    // 处理客户端数据
    while (1) {
        int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
        
        if (len < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 超时,继续等待
                continue;
            }
            ESP_LOGE(TAG, "接收数据错误: errno %d", errno);
            break;
        } else if (len == 0) {
            ESP_LOGI(TAG, "客户端 %s 断开连接", addr_str);
            break;
        } else {
            rx_buffer[len] = 0; // 添加null终止符
            ESP_LOGI(TAG, "从 %s 收到 %d 字节: %s", addr_str, len, rx_buffer);
            
            // 发送响应
            int tx_len = snprintf(tx_buffer, sizeof(tx_buffer), " server has received %d bytes", len);
            int sent = send(sock, tx_buffer, tx_len, 0);
            if (sent < 0) {
                ESP_LOGE(TAG, "发送失败: errno %d", errno);
                break;
            }
        }
    }
    
    // 关闭socket
    shutdown(sock, 0);
    close(sock);
    ESP_LOGI(TAG, "客户端 %s 处理结束", addr_str);
    vTaskDelete(NULL);
}


// TCP服务器任务
void tcp_server_task(void *pvParameters)
{
    char addr_str[128];
    int addr_family = AF_INET;
    int ip_protocol = IPPROTO_IP;
    
    struct sockaddr_in server_addr;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    
    // 创建socket
    int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
    if (listen_sock < 0) {
        ESP_LOGE(TAG, "无法创建socket: errno %d", errno);
        vTaskDelete(NULL);
        return;
    }
    
    // 设置socket选项 (允许地址重用)
    int opt = 1;
    setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    
    // 绑定socket
    int err = bind(listen_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (err != 0) {
        ESP_LOGE(TAG, "socket绑定失败: errno %d", errno);
        close(listen_sock);
        vTaskDelete(NULL);
        return;
    }
    
    // 开始监听
    err = listen(listen_sock, EXAMPLE_MAX_STA_CONN);
    if (err != 0) {
        ESP_LOGE(TAG, "socket监听失败: errno %d", errno);
        close(listen_sock);
        vTaskDelete(NULL);
        return;
    }
    
    ESP_LOGI(TAG, "TCP服务器已启动,监听端口: %d", PORT);
    
    while (1) {
        ESP_LOGI(TAG, "等待新的客户端连接...");
        
        struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
        int client_sock = accept(listen_sock, (struct sockaddr *)&client_addr, &client_len);
        
        if (client_sock < 0) {
            ESP_LOGE(TAG, "接受连接失败: errno %d", errno);
            continue;
        }
        
        // 将客户端IP转换为字符串
        inet_ntoa_r(client_addr.sin_addr, addr_str, sizeof(addr_str) - 1);
        ESP_LOGI(TAG, "新的客户端连接: IP=%s, 端口=%d", addr_str, ntohs(client_addr.sin_port));
        
        // 为客户端任务分配参数
        client_params_t *params = malloc(sizeof(client_params_t));
        if (params == NULL) {
            ESP_LOGE(TAG, "内存分配失败");
            close(client_sock);
            continue;
        }
        
        params->socket = client_sock;
        params->addr = client_addr;
        
        // 创建客户端任务
        if (xTaskCreate(client_task, "client_task", 4096, params, 5, NULL) != pdPASS) {
            ESP_LOGE(TAG, "无法创建客户端任务");
            free(params);
            close(client_sock);
        }
    }
    
    close(listen_sock);
    vTaskDelete(NULL);
}
void app_main(void)
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta();

    xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_SUCCESS, pdFALSE, pdFALSE, portMAX_DELAY);

    vTaskDelay(1000 / portTICK_PERIOD_MS);

     // 创建TCP服务器任务
     xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 5, NULL);
}

运行测试

I (1616) esp_netif_handlers: sta ip: 192.168.137.54, mask: 255.255.255.0, gw: 192.168.137.1
I (1616) wifi station: got ip:192.168.137.54
I (1616) wifi station: connected to ap SSID:zhaozhong password:12345678
I (2616) wifi station: TCP服务器已启动,监听端口: 8080
I (2616) wifi station: 等待新的客户端连接...
I (2616) main_task: Returned from app_main()
I (18386) wifi station: 新的客户端连接: IP=192.168.137.1, 端口=59883
I (18386) wifi station: 等待新的客户端连接...
I (18386) wifi station: 客户端任务启动: IP=192.168.137.1, 端口=59883
I (19296) wifi:<ba-add>idx:0 (ifx:0, d6:54:8b:b2:90:f3), tid:0, ssn:7, winSize:64
I (23296) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (28216) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (29146) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (58626) wifi station: 新的客户端连接: IP=192.168.137.230, 端口=49416
I (58626) wifi station: 等待新的客户端连接...
I (58626) wifi station: 客户端任务启动: IP=192.168.137.230, 端口=49416
I (58626) wifi station: 新的客户端连接: IP=192.168.137.230, 端口=49416
I (58626) wifi station: 等待新的客户端连接...
I (58626) wifi station: 客户端任务启动: IP=192.168.137.230, 端口=49416
I (78916) wifi station:192.168.137.230 收到 10 字节: 5588888811
I (87206) wifi station:192.168.137.230 收到 5 字节: hello
I (93646) wifi station:192.168.137.230 收到 5 字节: hello
I (98886) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (101326) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (106256) wifi station: 客户端 192.168.137.1 断开连接
  1. ESP32连接电脑创建的热点,并分配到了192.168.137.54地址。手机分配到了230地址
    在这里插入图片描述
  2. ESP32启动TCP服务器,然后用电脑网络助手和手机的网络助手连接。然后发送数据测试。
    在这里插入图片描述
  3. 可以实现多连接等功能。

二、 ESP32设置为静态IP

增加部分代码设置静态IP,然后在WiFi启动之前调用即可

// 静态IP配置
#define EXAMPLE_ESP_STATIC_IP      "192.168.137.100"
#define EXAMPLE_ESP_STATIC_GW      "192.168.137.1"
#define EXAMPLE_ESP_STATIC_NM      "255.255.255.0"

// 设置静态IP的函数
void set_static_ip()
{
    esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
    if (netif == NULL) {
        ESP_LOGE(TAG, "获取网络接口失败");
        return;
    }
    
    // 设置静态IP配置
    esp_netif_ip_info_t ip_info;
    memset(&ip_info, 0, sizeof(esp_netif_ip_info_t));
    ip_info.ip.addr = ipaddr_addr(EXAMPLE_ESP_STATIC_IP);
    ip_info.gw.addr = ipaddr_addr(EXAMPLE_ESP_STATIC_GW);
    ip_info.netmask.addr = ipaddr_addr(EXAMPLE_ESP_STATIC_NM);
    
    // 应用静态IP配置
    esp_netif_dhcpc_stop(netif);
    esp_netif_set_ip_info(netif, &ip_info);
    
    ESP_LOGI(TAG, "静态IP设置成功 (使用esp_netif)");
}


void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (password len => 8).
             * If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
             * to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to
             * WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.
             */
            .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
            .sae_pwe_h2e = ESP_WIFI_SAE_MODE,
            .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );


    // 在启动WiFi前设置静态IP
    set_static_ip();

    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }
}

进行测试

I (567) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (577) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
I (587) esp_netif_handlers: sta ip: 192.168.137.100, mask: 255.255.255.0, gw: 192.168.137.1
I (597) wifi station: got ip:192.168.137.100
I (597) wifi station: connected to ap SSID:zhaozhong password:12345678
I (647) wifi:AP's beacon interval = 102400 us, DTIM period = 3
I (1607) wifi station: TCP服务器已启动,监听端口: 8080
I (1607) wifi station: 等待新的客户端连接...
I (1607) main_task: Returned from app_main()
I (8847) wifi station: 新的客户端连接: IP=192.168.137.1, 端口=54251
I (8847) wifi station: 等待新的客户端连接...
I (8847) wifi station: 客户端任务启动: IP=192.168.137.1, 端口=54251
I (11307) wifi:<ba-add>idx:0 (ifx:0, d6:54:8b:b2:90:f3), tid:0, ssn:6, winSize:64
I (13447) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (14987) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (15907) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (21127) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn
I (21437) wifi station:192.168.137.1 收到 20 字节: http://www.cmsoft.cn

IP已经固定为192.168.137.100 静态IP设置正常。

相关文章:

  • 机器学习的四种主流学习方式
  • QOpenGLWidget动态加载功能实现教程(Qt+OpenGL)
  • 如何同步fork的更新
  • 【IDEA的个性化配置】
  • 备赛蓝桥杯之第十六届模拟赛2期职业院校组第五题:文本自动生成器
  • SQL Server 2022常见问题解答
  • Mybatis笔记(上)
  • VsCode启用右括号自动跳过(自动重写) - 自录制gif演示
  • 26考研——栈、队列和数组_数组和特殊矩阵(3)
  • 力扣刷题-热题100题-第24题(c++、python)
  • 代码规范之Variable Names变量名
  • 如何使用 CSS 实现多列布局,有哪些注意事项
  • 一款可查看手机详细配置信息的小工具,简单直观,自动识别硬件信息
  • 创建一个服务器启动自动执行的脚本,设置默认路由
  • LUMOS: Language-Conditioned Imitation Learning with World Models
  • QT三 自定义控件,自定义控件的事件处理自定义事件过滤,原始事件过滤
  • 爬虫——将数据保存到MongoDB中
  • conda极速上手记录
  • 如何部署自己的本地大模型
  • Hadoop三 分布式sql计算hive入门
  • 首开股份:一季度净利润亏损约10.79亿元,签约金额63.9亿元
  • 全国人民代表大会常务委员会公告〔十四届〕第十号
  • 南京航空航天大学启动扁平化改革:管理岗规模控制在20%,不再统一设科级机构
  • 初步结果显示加拿大自由党赢得大选,外交部回应
  • 绿地控股:今年一季度营业收入356亿元,中高层管理人员带头降薪
  • 伊朗内政部长:港口爆炸由于“疏忽”和未遵守安全规定造成