#功能描述
嵌入式板子上有应用程序,调用libcurl,有两个子线程分别负责不同功能。
线程1:负责将文件传输至远程FTP服务器
线程2:负责与另一台嵌入式设备上的HTTP服务器协议进行通信(此流程为了降低功耗服务器只有在固定时间上电,执行完就断电)
#问题现象
在运行3个月后线程2开始出现问题,curl_easy_perform() failed[7]: Couldn't connect to server 无法连接至HTTP服务器,线程1始终正常在运行。
HTTP服务器为了降低功耗只有在固定时间上电,HTTP交互完就会断电。用别的设备连接过是没有问题的。
问题出现在线程2,不知道该如何排查
两个线程都是使用的下面流程
curl_easy_setopt -》 curl_easy_perform -》curl_easy_cleanup
如果说是网络资源耗尽导致无法再次创建链接,那么FTP传输也应该受影响才对,就不知道该怎么排查了
目前确定与HTTP服务器交互时,HTTP是正常启动的,而且HTTP是局域网内部链接,FTP与HTTP处于不同网段
这是与FTP交互的部分
CURL *curl = curl_easy_init();
for(i = 0;i < dbCount;i++)
{
sprintf(dbName,"%s/FTP%d.db",FTP2DIR,dbNum[i]);
printf("dbName %s\n",dbName);
if(1 == ftp_upload(dbName,FTP2,&uploadCount,curl))
{
break;
}
}
curl_easy_cleanup(curl);
//ftp_upload
static int32 ftp_upload(const char8 *dbName,uint8 ftpNum,uint32 *uploadCount,CURL *curl)
{
const COM_HANDLER_T *pDispHandler = NULL;
if(*uploadCount >= MAX_UPLOAD_COUNT_ONE_TURN || curl == NULL)
{
return 0;
}
FTPMSG msg;
struct stat file_info;
CURLcode res;
curl_off_t fsize;
char8 auth[100] = {0};
char8 ftpfile[150] = {0};
char8 errmsg[300] = {0};
int32 ret = 0;
FILE *hd_src;
int32 rowNumber = 0;
while(1)
{
ftpsql_request(ftpNum);
rowNumber = get_uploadFileNumber(dbName,ftpNum);
ftpsql_release(ftpNum);
if(rowNumber == 0 || rowNumber < 0)
{
printf("file need upload is none in %s\n",dbName);
return 0;
}
memset(auth,0,sizeof(auth));
memset(ftpfile,0,sizeof(ftpfile));
memset(errmsg,0,sizeof(errmsg));
ftpsql_request(ftpNum);
get_uploadMessage(dbName,&msg,ftpNum);
ftpsql_release(ftpNum);
if(stat(msg.fileName, &file_info) < 0) // /mnt/mmc1 目录下未找到
{
sprintf(errmsg,"ftpupload: Couldn't open %s: %s",msg.fileName, strerror(errno));
log_WriteCurrentMessage(errmsg);
printf("%s",errmsg);
ftpsql_request(ftpNum);
set_uploadMessage(dbName,&msg,UPLOAD_NOTEXIST,ftpNum);
ftpsql_release(ftpNum);
continue;
}
fsize = (curl_off_t)file_info.st_size;
hd_src = fopen(msg.fileName, "rb");
sprintf(auth,"%s:%s",msg.ftpUser,msg.ftpPasswd);
ret = compose_ftpfilename(ftpfile,msg.fileName,msg.ftpDir,msg.ftpDirMode,msg.ftpIP,msg.ftpPort);
if(ret != 0)
{
memset(errmsg,0,sizeof(errmsg));
sprintf(errmsg,"compose_ftpfilename %s failed,ret %d",msg.fileName,ret);
log_WriteCurrentMessage(errmsg);
ret = compose_ftpfilename2(ftpfile,msg.fileName,msg.ftpDir,msg.ftpIP,msg.ftpPort);
if(ret != 0)
{
ftpsql_request(ftpNum);
set_uploadMessage(dbName,&msg,UPLOAD_FAIL,ftpNum);
ftpsql_release(ftpNum);
}
continue;
}
memset(errmsg,0,sizeof(errmsg));
sprintf(errmsg,"ftpfile %s",ftpfile);
log_WriteCurrentMessage(errmsg);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_URL, ftpfile);
curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,(curl_off_t)fsize);
curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 1); //目录不存在时,上传文件时,先创建目录
//curl_easy_setopt(curl, CURLOPT_INTERFACE, port);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 120);
curl_easy_setopt(curl, CURLOPT_USERPWD,auth); //user:passwd
curl_easy_setopt(curl, CURLOPT_UPLOAD_BUFFERSIZE, 204800L);
curl_easy_setopt(curl, CURLOPT_VERBOSE,1L);
res = curl_easy_perform(curl);
printf("\n\n\n");
fclose(hd_src);
if(res != CURLE_OK)
{
sprintf(errmsg,"FTP%d,ftpupload %s failed,[%d]%s",ftpNum,msg.fileName,res,curl_easy_strerror(res));
log_WriteCurrentMessage(errmsg);
strcat(errmsg,"\r\n");
pDispHandler = drv_GetAutoDisplayHandler("CAPTURE");
if (pDispHandler != NULL)
{
pDispHandler->sendBuffer(pDispHandler->handleID, errmsg, strlen(errmsg));
}
printf("%s\n",errmsg);
ftpsql_request(ftpNum);
set_uploadMessage(dbName,&msg,UPLOAD_FAIL,ftpNum);
ftpsql_release(ftpNum);
curl_easy_reset(curl);
update_uploadFailedCounts();
return 1;
}
else
{
sprintf(errmsg,"FTP%d,ftpupload %s success",ftpNum,msg.fileName);
log_WriteCurrentMessage(errmsg);
pDispHandler = drv_GetAutoDisplayHandler("CAPTURE");
strcat(errmsg,"\r\n");
if (pDispHandler != NULL)
{
pDispHandler->sendBuffer(pDispHandler->handleID, errmsg, strlen(errmsg));
}
ftpsql_request(ftpNum);
set_uploadMessage(dbName,&msg,UPLOAD_SUCCESS,ftpNum);
ftpsql_release(ftpNum);
*uploadCount = *uploadCount + 1;
curl_easy_reset(curl);
update_uploadFailedCounts_cleanUp();
}
if(*uploadCount >= MAX_UPLOAD_COUNT_ONE_TURN)
{
break;
}
}
return 0;
}
这是与HTTP交互的部分
int get_IdentificationModuleState(MemoryStruct chunk,char *jsonMsg,char *recbuf)
{
char logmsg[200] = {0};
char url[200] = {0};
uint8 ip[4];
drv_GetRemoteHttpServerIP(ip);
uint16 port = drv_GetRemoteHttpServerPort();
CURLcode res;
CURL *curl = curl_easy_init();
//memset(chunk.memory,0,sizeof(chunk.memory));
chunk.size = 0;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type:application/json");
headers = curl_slist_append(headers, "charset=UTF-8");
headers = curl_slist_append(headers, "Expect:");
if(curl)
{
sprintf(url,"http://%u.%u.%u.%u:%d/v1/state",ip[0],ip[1],ip[2],ip[3],port);
//curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.14.147:80/v1/state");
curl_easy_setopt(curl, CURLOPT_URL, url);
//设置请求头信息
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
//不接收头信息
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
//尝试连接等待时间 5s
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5L);
//执行最大等待时间 10s
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
//curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
//curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 10L);
//curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 5L);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
//设置POST的JSON数据
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonMsg);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(jsonMsg));
//设置接受处理
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_post_callback);
//禁用链接池功能
//curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1l);
/* get verbose debug output please */
if(1)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
//curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, 1L);
}
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
{
sprintf(logmsg,"get_IdentificationModuleState,curl_easy_perform() failed[%d]: %s",res,curl_easy_strerror(res));
printf("%s\n",logmsg);
log_WriteCurrentMessage(logmsg);
}
/* always cleanup */
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
else
{
return -1;
}
if(chunk.memory != NULL)
{
//memset(recbuf,0,sizeof(recbuf));
strncpy(recbuf,chunk.memory,chunk.size);
printf("RECV:\n%s\n",recbuf);
}
return res;
}