rust如何在木板上上传图片_C调用Rust动态链接库实现Http文件上传

絮絮叨叨

笔者最近做一个项目,跟一个写C的小伙一起开发。笔者原本是用Java写服务端接口的,那个小伙用C写客户端。客户端某个功能需要图片到服务端的Http接口上。

而写C的小伙目前对Http这块还不熟,加上C发起Http请求比较麻烦。于是笔者就想用Rust开发一个动态库链接库给C调用。在动态链接库公开一个函数,参数是Http的请求地址和图片,如果上传成功就返回1,失败就返回0。

Rust函数大致如下:

#[no_mangle]

pub extern "C" fn post_image(c_url: *const c_char, payload_ptr: *const payload_t) -> i32 {

// TODO

}

*const c_char用于接收来自C里面的字符串,在C里面对应的是const char *

*const payload_t是用来接收来自C的图片数据,在这里定应了一个Rust Struct

#[repr(C)]

pub struct payload_t {

data: *const u8,

len: c_int

}

这里的data表示接收一个来自C的指针,而len表示指针的长度。

下面来看整个扩展的编写过程。

开始写Rust代码

1、用cargo创建一个rust工程

cargo new mylib

cd mylib

2、在Cargo.toml文件中配置[lib]和[dependencies]

[lib]

name = "mylib"

crate-type = ["cdylib"]

path = "src/lib.rs"

[dependencies]

reqwest = {version = "0.10.0", features = ["blocking"] }

base64 = "0.11.0"

3、下面关键的步骤来了,编写lib.rs代码

use std::os::raw::{c_char, c_int};

use std::ffi::CStr;

use std::error::Error;

#[repr(C)]

pub struct payload_t {

data: *const u8,

len: c_int

}

#[no_mangle]

pub extern "C" fn post_image(c_url: *const c_char, payload_ptr: *const payload_t) -> i32 {

// 在这里开始一步步将c字符串转换成&str

let c_str: &CStr = unsafe {

CStr::from_ptr(c_url)

};

if let Err(err) = c_str.to_str() {

eprintln!("{}", err.description());

return 0;

}

let str_url = c_str.to_str().unwrap();

// 在这里开始将c传过来的文件,转换成&[u8]

let r_payload = unsafe {

*Box::from_raw(payload_ptr as *mut payload_t)

};

let bytes = unsafe {

std::slice::from_raw_parts(r_payload.data, r_payload.len as usize)

};

// 开始上传文件

if post(str_url, bytes) {

return 1;

}

return 0;

}

fn post(str_url: &str, payload: &[u8]) -> bool {

let client = reqwest::blocking::Client::new();

let body_base64 = base64::encode(payload);

if let Ok(res) = client.post(str_url).body(body_base64).send() {

let status = res.status();

println!("{:?}", res);

println!("{:?}", res.text());

if status == 201 {

return true;

}

};

return false;

}

在这里post函数中,把payload: &[u8]转为base64在上传的,实际不转也可以。主要得看接收文件的Http接口是如何做的。

用cbindgen生成头文件

1、安装cbindgen

cargo install --force cbindgen

2、在工程的根目录下编写cbindgen.toml文件

language = "C"

这里很简单,指定生成头文件的语言为C就可以了。这个文件为空也是可以的。

3、生成头文件

cbindgen --config cbindgen.toml --crate mylib --output mylib.h

编译动态链接库

cargo build

笔者用的是Mac系统,在target/debug目录下生成了libmylib.dylib文件,这个就是动态链接库了。接下来在这个目录下创建一个test.c文件来测试。

开始写C代码来测试

1、编写test.c

#include "mylib.h"

#include

int file_size(char * file_name)

{

FILE *fp = fopen(file_name, "rb");

int size;

if (fp == NULL)

return -1;

fseek(fp, 0, SEEK_END);

size = ftell(fp);

fclose(fp);

return size;

}

int main()

{

int size = 0;

const char *c_url = "http://localhost:8080/upload";

size = file_size("test.png");

FILE *fp;

char *buffer = (char*)malloc(sizeof(char)*size);

fp = fopen("test.png", "rb");

if (fp == NULL)

return 0;

fread(buffer, 1, size, fp);

fclose(fp);

payload_t payload;

payload_t *payload_ptr = malloc(sizeof(payload));

const uint8_t *buffer_ptr = (uint8_t *)buffer;

payload_ptr->data = buffer_ptr;

payload_ptr->len = size;

int32_t flag = post_image(c_url, payload_ptr);

if(flag == 1)

{

printf("%s\n", "上传成功");

}

else

{

printf("%s\n", "上传失败");

}

free(buffer);

buffer = NULL;

return 0;

}

这里是用C代码上传本地的一张test.png图片到服务端。测试时记得复制一张图片到C代码所在目录。

2、编译C,并运行

gcc test.c -L ./ -lmylib -o test

./test

mylib就是动态链接库的名称.

就这样结束了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值