功能接口封装&测试

JLKJ天线控制器升级软件,ETC2.0的。接口功能:通过URL和资源名下载。

1.选择使用libcurl实现业务功能。下载curl-8.13.0源码包进行编译,并使用libcurl.a和头文件。

~/zhoulu/curl-8.13.0$ ./configure --host=arm-none-linux-gnueabi --prefix ~/zhoulu/ --without-ssl --without-libpsl --without-zlib --disable-shared --enable-static

~/zhoulu/curl-8.13.0$make

~/zhoulu/curl-8.13.0$make install

2.使用百度AI写的接口代码,稍微修改了一下直接使用。代码如下:

#include <stdio.h>
#include <curl/curl.h>

// 写入数据的回调函数,将接收到的数据保存到文件
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
    return fwrite(ptr, size, nmemb, stream);
}

int url_resource_get(char *resource_url, char *resource_name) 
{
    CURL *curl;
    FILE *fp;
    CURLcode res;

    // 全局初始化libcurl
    curl_global_init(CURL_GLOBAL_DEFAULT);

    // 初始化CURL句柄
    curl = curl_easy_init();
    if (!curl) {
        fprintf(stderr, "Error: Failed to initialize CURL.\n");
        return 1;
    }

    // 以二进制写入模式打开文件
    fp = fopen(resource_name, "wb");
    if (!fp) {
        fprintf(stderr, "Error: Failed to open file %s\n", resource_name);
        curl_easy_cleanup(curl);  // 清理CURL句柄
        curl_global_cleanup();    // 全局清理
        return 1;
    }

    // 设置CURL选项
    curl_easy_setopt(curl, CURLOPT_URL, resource_url);              // 设置URL
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); // 回调函数
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);         // 文件指针
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);    // 跟随重定向
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); // 设置User-Agent

    // 执行下载操作
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fprintf(stderr, "Error: %s\n", curl_easy_strerror(res));
    }

    // 清理资源
    fclose(fp);
    curl_easy_cleanup(curl);
    curl_global_cleanup();

    return 0;
}

3.使用之前百度AI写的多线程的main.c,来调用功能接口进行测试。代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>
#include <signal.h>

#define NUM_THREADS 1

extern int url_resource_get(char *resource_url, char *resource_name);

bool g_program_stop_flag = false;

// 统一的线程函数
void* thread_function(void* arg)
{
    int thread_num = *(int*)arg; // 获取线程编号
    while (1)
    {
        switch (thread_num)
        {
        case 1:
            url_resource_get("http://192.168.8.2:8000/Makefile", "Makefile");
            sleep(3);
            break;
        default:
            break;
        }
        if (g_program_stop_flag)
            break;
    }
    return NULL;
}
static void signal_handler(int sig)
{
    const char *sig_name;
    switch (sig) {
        case SIGINT:  sig_name = "SIGINT";  break;
        case SIGTERM: sig_name = "SIGTERM"; break;
        case SIGQUIT: sig_name = "SIGQUIT"; break;
        case SIGSEGV: sig_name = "SIGSEGV"; break;
        case SIGFPE:  sig_name = "SIGFPE";  break;
        default:      sig_name = "Unknown"; break;
    }

    // 输出信息(注意:此处用stdio函数不安全,仅用于演示)
    fprintf(stderr, "\nCaught signal: %s (%d)\n", sig_name, sig);

    // 针对不同信号的逻辑
    switch (sig) {
        case SIGSEGV:
            // 段错误:记录信息并终止(无法安全恢复)
            fprintf(stderr, "Segmentation fault! Exiting...\n");
            break;
        case SIGFPE:
            // 浮点异常:记录信息并终止
            fprintf(stderr, "Arithmetic error! Exiting...\n");
            break;
        default:
            // SIGINT/SIGTERM/SIGQUIT:标记退出循环
            fprintf(stderr, "Graceful shutdown...\n");
            g_program_stop_flag = true;
            break;
    }

    // 注意:SIGSEGV/SIGFPE处理后应直接终止,避免未定义行为
    if (sig == SIGSEGV || sig == SIGFPE) {
        signal(sig, SIG_DFL); // 恢复默认行为
        raise(sig);           // 重新触发信号以生成核心转储(如果需要)
    }
}
static void setup_signal_handlers()
{
    struct sigaction sa;
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART; // 自动重启被中断的系统调用

    // 注册需要处理的信号
    sigaction(SIGINT,  &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGQUIT, &sa, NULL);
    sigaction(SIGSEGV, &sa, NULL);
    sigaction(SIGFPE,  &sa, NULL);
    signal(SIGPIPE,SIG_IGN);
}
int main(int argc, char *argv[])
{
    int i;
    pthread_t threads[NUM_THREADS];
    int thread_nums[NUM_THREADS]; // 存储线程编号

    setup_signal_handlers();

    // 逐个创建线程
    for (i = 0; i < NUM_THREADS; i++)
    {
        thread_nums[i] = i + 1; // 线程编号从1开始
        int rc = pthread_create(&threads[i], NULL, thread_function, &thread_nums[i]);
        if (rc) {
            fprintf(stderr, "Error creating thread %d: %d\n", i+1, rc);
            exit(EXIT_FAILURE);
        }
        fprintf(stdout, "jl_v2x_app_obu start task Thread-%d (ID: %lu) \n", i+1, threads[i]);
    }
    // 逐个等待线程
    for (i = 0; i < NUM_THREADS; i++)
    {
        pthread_join(threads[i], NULL);
        fprintf(stdout, "jl_v2x_app_obu task Thread-%d (ID: %lu) stop\n", thread_nums[i], threads[i]);
    }

    fprintf(stdout, "jl_v2x_app_obu Graceful shutdown\n");
    return 0;
}

4.编译生成可执行程序。

~/zhoulu$ arm-linux-gcc appv_main.c appv_url_get.c -o appv_main -I./include -L./lib -lcurl -lpthread -lrt

5.搭建测试使用的http服务端。

在Windows11系统中安装python,直接使用python内置的简单http服务器功能。建立了http服务目录python_http_server并启动http服务。放置了资源文件Makefile到目录中。

PS C:\Users\liudo\python_http_server> python.exe -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

6.在JLKJ天线控制器上运行程序进行接口功能测试。截图如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值