最近有一个棘手的问题,涉及到数据安全的考量,原先非常方便的使用python进行http服务的代码需要改成c语言来实现,我的方案是直接用c调用libcurl的库来实现,这里面遇到不少问题,后来出于不同的linux环境通用的原因又使用了docker来打包运行,下面就是详细内容。
本身这个库对c语言就有很好的支持,官网上就有现成的c语言的api使用介绍和代码demo。我所使用的是libcurl最简单的接口curl_easy_***,首先先看下环境里是否已经安装了curl命令,curl -V,若已安装的话,可直接使用系统环境里的libcurl的相关库,没有的话需要自己去官网下载源码编译。
cd源码目录
#配置编译结果存放路径
./configure --prefix=/***/***/***/
make
make install
编完之后会在设定的目录下产生一个curl目录,有如下内容:
编译业务代码的时候就可以指定lib作为依赖库了
这里给出一个很简单的demo
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "include/curl/curl.h"
#include "include/d_t_1.h"
#include "include/d_t_s.h"
#include "include/d_t_t.h"
/**
* curl 访问url操作
* 目前使用的是libcurl的easy接口
* 返回最终发送失败的url条数
*/
int url_func(char *urls[], int len){
int ret;
int n = 0;
//error count
int s = 0;
FILE *ef = fopen(err_url,"w+");
FILE *sf = fopen(suc_url,"a+");
FILE *lf = fopen(log_path, "a+");
CURL *curl;
CURLU *urlp;
CURLUcode uc;
if(ef == NULL || sf == NULL || lf == NULL)
{
printf("%s file open failed! \n", date_time);
return FILE_OPEN_ERROR;
}
while(n < len){
//全局初始化接口
//涉及到一些全局常量的初始化
curl_global_init(CURL_GLOBAL_ALL);
//easy接口初始化返回句柄
curl = curl_easy_init();
if (!curl) {
//fputs("couldn't init curl!", lf);
continue;
}
//下面是各种设置,具体可以参考官网的介绍
//设置各种参数,这里是设置要访问的url
curl_easy_setopt(curl, CURLOPT_URL, urls[n]);
//设置代理
curl_easy_setopt(curl, CURLOPT_PROXY, _HTTP_PROXY_);
curl_easy_setopt(curl, CURLOPT_PROXY, _HTTPS_PROXY_);
//设定为不验证证书和HOST
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
//访问url
ret = curl_easy_perform(curl);
printf("\n");//用于作为url终端打印的间隔
if(ret != CURLE_OK){
//访问完毕、清理退出
curl_easy_cleanup(curl);
fprintf(lf, "%s url access failed, error code : %d \n", date_time, ret);
fprintf(ef, "%s\n", urls[n]);
n++;
continue;
}
curl_easy_cleanup(curl);
fprintf(sf, "%s\n", urls[n]);
n++;
s++;
}
//全局清理退出
curl_global_cleanup();
fclose(ef);
fclose(sf);
fclose(lf);
return s;
}
我所用的是最简单的easy端口,每次进行一次http操作都需要先init再cleanup,切记不能复用,如果需要增强吞吐量进行并行操作需要使用multiple接口,可以参考官网介绍。
编译可执行文件 a.out
gcc geb_url.c -L./curl/lib -lcurl
编译sdk库:a.so
gcc geb_url.c -fPIC -L./curl/lib -lcurl -Wl,-rpath ./curl/lib -Wl,-rpath-link ./curl/lib -shared -o a.so
上述两个都是指明了依赖库的路径,如果系统已经安装了curl,就可以省去-L、-Wl,-rpath-link选项
环境的差异会导致各种奇怪的错误,所以一定要注意。
curl版本:
curl 7.29.0 (x86_64-redhat-linux-gnu) libcurl/7.29.0 NSS/3.19.1 Basic ECC zlib/1.2.7 libidn/1.28 libssh2/1.4.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz
libcurl信息:
libcurl/7.29.0 NSS/3.19.1 Basic ECC zlib/1.2.7 libidn/1.28 libssh2/1.4.3
系统版本:
CentOS Linux release 7.2.1511 (Core)
Linux *** 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
因为实际运行环境可能有各种各样的问题,所以我们的sdk最好排除环境能够直接运行,这里采用了docker的方法,在docker搭一套测试通过的linux环境来跑libcurl的sdk。
有关docker的介绍这里就不说了,直接介绍我是如何使用的
docker的下载安装和测试:
有多种方式,可以通过命令行下载,也可以下载二进制包,我选择的是后者,进入官网,下载对应的二进制包链接: https://download.docker.com/linux/static/stable/x86_64/,
本来下载完还需要手动安装配置,幸好有网友提供了安装脚本:https://github.com/liumiaocn/easypack/blob/master/docker/install-docker.sh,
前面从安装到测试是否成功这几步可以参考这篇文章:https://www.kubernetes.org.cn/3831.html
有两种方式:
1、通过dockfile构建
2、通过基础镜像构建
我选择的是第2种,首先需要下载基础的linux镜像
#前面是系统类型后面是版本号
docker pull centos:7.2.1511
如果本地没有该镜像会下载,下载完成后,进入镜像
docker run -it centos:7.2.1511
下面就进入了镜像,就是centos系统了,需要安装什么就装吧,一般来说可以先安装vim,我还安装了curl,接下来就是保存我们修改过的镜像作为基础镜像。
这一块内容可以参考文章:https://blog.csdn.net/chanmufeng/article/details/80459607
最后的话,可能就是涉及到镜像与宿主机系统之间的文件拷贝、镜像的导入导出等等内容,可参考:https://blog.csdn.net/hewei_bj/article/details/80200050、
https://www.cnblogs.com/ksir16/p/6553851.html等文章