对于嵌入式设备资源较少或者运行环境较简单的环境下,如果只是简单上传一张图片到阿里云OSS服务器的话,移植阿里云OSS的SDK就是一件性价比很低而且不一定能实现的事情了。那就得考虑自己实现一套简单的、最基础的图片上传功能。阿里云OSS提供了REST API方式的图片上传接口,即通过HTTP方式将图片PUT到OSS服务器。API接口接口可参考:https://help.aliyun.com/zh/oss/developer-reference/api-reference/?spm=a2c4g.11186623.0.0.1e436d4fztnTzz
上传一张图片到阿里云OSS服务器主要分为如下几个步骤:
1. 连接aliyun OSS服务器;
2. 生成PUT语句并发送;
3. 发送图片;
4. 接收服务器返回的操作结果,判定是否需要重传。
以下具体贴一下代码实现。
一、连接阿里云OSS服务器
`int app_oss_connect_server(void)
{
int iFd = -1;
struct hostent *pHostEnt = NULL;
struct sockaddr_in struServAddr;
pHostEnt = gethostbyname(APP_OSS_DOMAIN_NAME);
if (NULL == pHostEnt)
{
ESP_LOGE(TAG, "DNS lookup failed");
return ESP_FAIL;
}
iFd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == iFd)
{
ESP_LOGE(TAG, "Socket create error!");
return ESP_FAIL;
}
memset(&struServAddr, 0, sizeof(struServAddr));
struServAddr.sin_family = AF_INET;
struServAddr.sin_port = htons(APP_OSS_CONN_PORT);
struServAddr.sin_addr = *((struct in_addr*)pHostEnt->h_addr);
//ESP_LOGI(TAG, "Connect to ali-oss server: %s.", inet_ntoa(struServAddr.sin_addr));
if (0 != connect(iFd, (struct sockaddr *)&struServAddr, sizeof(struct sockaddr)))
{
ESP_LOGE(TAG, "Connect to ali-oss server error!");
close(iFd);
iFd = ESP_FAIL;
}
return iFd;
}`
APP_OSS_DOMAIN_NAME就是购买OSS服务分配的域名,形式如:xxxx.oss-cn-hangzhou.aliyuncs.com
二、生成PUT语句并发送+发送图片+接收服务器答复
`int app_oss_picture_upload(int iFd)
{
camera_fb_t *pPicFB = NULL;
char szPicName[APP_OSS_PIC_NAME_LEN] = {0};
char szDateTime[32] = {0};
char szAuthStr[128] = {0};
char szOssHeader[512] = {0};
struct tm *pTm = NULL;
int b64Len = 0;
unsigned char hmac[20] = {0};
char b64[((20 + 1) * 4) / 3] = {0};
char b64Str[((20 + 1) * 4) / 3+1] = {0};
int wrRet = 0;
int wrCnt = 0;
fd_set struFdSet;
struct timeval struTV;
int iRet = -1;
pPicFB = esp_camera_fb_get();
if (!pPicFB) {
ESP_LOGE(TAG, "Camera capture failed");
goto errExit;
}
/* Fill the header content */
memset(&struTV, 0, sizeof(struTV));
tTime = time(NULL);
pTm = gmtime(&tTime);
gettimeofday(&struTV, NULL);
snprintf(szPicName, sizeof(szPicName),
"/DIR/%4d%02d%02d_%02d%02d%02d%03d.jpg",
pTm->tm_year+1900, pTm->tm_mon+1, pTm->tm_mday,
pTm->tm_hour, pTm->tm_min, pTm->tm_sec, (int)((struTV.tv_usec/1000)%1000));
app_oss_global_pic_name_set(szPicName);
snprintf(szDateTime, sizeof(szDateTime),
"%s, %02d %s %04d %02d:%02d:%02d GMT",
week[pTm->tm_wday], pTm->tm_mday, months[pTm->tm_mon],
pTm->tm_year+1900, pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
snprintf(szAuthStr, sizeof(szAuthStr),
"PUT\n\nimage/jpeg\n%s\n%s", szDateTime, szPicName);
//ESP_LOGI(TAG, "szAuthStr: %s(%d)", szAuthStr, strlen(szAuthStr));
hmac_sha1((unsigned char*)APP_OSS_ACCESS_KEY_SECRET,
strlen(APP_OSS_ACCESS_KEY_SECRET),
(unsigned char*)szAuthStr, strlen(szAuthStr), hmac);
b64Len = oss_base64_encode(hmac, 20, b64);
memcpy(b64Str, b64, b64Len);
memset(szOssHeader, 0, APP_OSS_HEADER_BUFSIZE);
snprintf(szOssHeader, APP_OSS_HEADER_BUFSIZE,
"PUT %s HTTP/1.1\r\n" \
"User-Agent: esp-idf/1.0 esp32\r\n" \
"Host: %s\r\n" \
"Accept: */*\r\n" \
"Content-Length: %d\r\n" \
"Content-Type: image/jpeg\r\n" \
"Date: %s\r\n" \
"Authorization: OSS %s:%s\r\n\r\n",
szPicName, APP_OSS_DOMAIN_NAME, pPicFB->len, szDateTime,
APP_OSS_ACCESS_KEY_ID, b64Str);
wrCnt = write(iFd, szOssHeader, strlen(szOssHeader));
if (wrCnt <= 0)
{
ESP_LOGE(TAG, "OSS send header to server error!");
goto errExit;
}
wrCnt = write(iFd, pPicFB->buf, pPicFB->len);
if (wrCnt <= 0)
{
ESP_LOGE(TAG, "OSS send picture to server error!");
goto errExit;
}
memset(&struTV, 0, sizeof(struTV));
memset(&struFdSet, 0, sizeof(struFdSet));
struTV.tv_sec = 5;
struTV.tv_usec = 0;
FD_ZERO(&struFdSet);
FD_CLR(iFd, &struFdSet);
FD_SET(iFd, &struFdSet);
wrRet = select(iFd + 1, &struFdSet, 0, 0, &struTV);
if (wrRet > 0)
{
if (FD_ISSET(iFd, &struFdSet))
{
memset(szOssHeader, 0, APP_OSS_HEADER_BUFSIZE);
wrCnt = read(iFd, szOssHeader, APP_OSS_HEADER_BUFSIZE-1);
if (wrCnt > 0)
{
//ESP_LOGI(TAG, "OSS Response: %s", szOssHeader);
if (NULL != strstr(szOssHeader, "200 OK"))
{
ESP_LOGI(TAG, "APP OSS upload picture ok!");
iRet = 0;
}
else
{
ESP_LOGE(TAG, "APP OSS upload picture failed!");
}
}
else
{
ESP_LOGE(TAG, "OSS read response error!");
}
}
}
else
{
ESP_LOGE(TAG, "OSS wait for response select error or timeout!");
}
errExit:
if (pPicFB)
{
esp_camera_fb_return(pPicFB);
pPicFB = NULL;
}
return iRet;
}`
这里最主要就是header的生成,需要注意的时日期时间还得是UTC 0时区的时间,不然服务器会报错误。
base64使用普通的那种就可以了。
对于删除图片等其他操作,流程也类似。有问题欢迎留言讨论。
谢绝转载!
标签:Cj,pTm,OSS,APP,ESP,iFd,tm,ESP32
From: https://www.cnblogs.com/kymars/p/18289141