原创: 冬冬他哥哥
链接: https://www.cnblogs.com/xietianjiao/p/13260021.html.
http协议是建立在TCP/IP协议之上应用层协议,默认端口为80,8080
http协议的的特点是无状态,无连接
利用抓包工具httpwatch可以获取报文
http协议的报文传输的是ASCII码,在TCP/IP协议之上,主要主要分为三部分
请求行、请求头、请求体
第一行,包含三个信息:请求方式,url,http协议版本
GET 请求
GET /books/?sex=man&name=Professional HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Connection: Keep-Alive
POST 请求
POST / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive
sex=man&name=Professional
区别:
1、url可见性:
get,参数url可见;
post,url参数不可见
2、数据传输上:
get,通过拼接url进行传递参数;
post,通过body体传输参数
3、缓存性:
get请求是可以缓存的
post请求不可以缓存
4、后退页面的反应
get请求页面后退时,不产生影响
post请求页面后退时,会重新提交请求
5、传输数据的大小
get一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)
post请求传输数据的大小根据php.ini 配置文件设定,也可以无限大。
6、安全性
这个也是最不好分析的,原则上post肯定要比get安全,毕竟传输参数时url不可见,但也挡不住部分人闲的没事在那抓包玩。安全性个人觉得是没多大区别的,防君子不防小人就是这个道理。对传递的参数进行加密,其实都一样。
本质区别:
GET产生一个TCP数据包;POST产生两个TCP数据包。
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
浏览器向服务器发送一些状态数据,标识数据等等
一个信息一行,包括信息名:信息值 按行分隔
User-Agent: firefox//表示发送请求的浏览器(请求代理端)是firefox
Host: shop.100.com//表示请求的主机域名(基于域名的虚拟主机就是靠这个头判断的)
Cookie:name=itcast//浏览器携带的cookie数据。
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive
注意,请求头信息,需要使用一个空行结束!
请求代理端项服务器端,发送的请求数据!
典型的就是POST形式发送的表单数据!
get请求,没有请求主体部分!get数据是在请求行中的url上进行传递的!
响应包括:响应行、响应头、响应体
响应行包括:协议版本、状态码、状态消息
典型的:
1xx:消息
2xx:成功
3xx:请求被重定向
4xx:浏览器端错误
5xx:服务器端错误
典型:
500 服务器内部错误
404 请求的页面没有找到
403 没有权限
200 请求成功
Content-Type: text/html 内容类型,告知浏览器接下来发送的响应主体数据是什么格式!
Content-Length: 响应主体数据的长度!
Date: 响应的时间。GMT时间!
主要的响应数据,在浏览器的主体区域显示的数据都是相应主体!
注意,每行,包括相应行和响应头,都需要一个 \r\n结尾
http协议是明文传输的,因此很容易被截取和解析,泄漏个人数据。https协议是在http和tcp之间多添加了一层,进行身份验证和数据加密。
① 客户端将它所支持的算法列表和一个用作产生密钥的随机数发送给服务器
② 服务器从算法列表中选择一种加密算法,并将它和一份包含服务器公用密钥的证书发送给客户端;该证书还包含了用于认证目的的服务器标识,服务器同时还提供了一个用作产生密钥的随机数 [2] ;
③ 客户端对服务器的证书进行验证(有关验证证书,可以参考数字签名),并抽取服务器的公用密钥;然后,再产生一个称作 pre_master_secret 的随机密码串,并使用服务器的公用密钥对其进行加密(参考非对称加 / 解密),并将加密后的信息发送给服务器 [2] ;
④ 客户端与服务器端根据 pre_master_secret 以及客户端与服务器的随机数值独立计算出加密和 MAC密钥(参考 DH密钥交换算法) [2] ;
⑤ 客户端将所有握手消息的 MAC 值发送给服务器 [2] ; ⑥ 服务器将所有握手消息的 MAC 值发送给客户端
明文: 明文指的是未被加密过的原始数据。
密文:明文被某种加密算法加密之后,会变成密文,从而确保原始数据的安全。密文也可以被解密,得到原始的明文。
密钥:密钥是一种参数,它是在明文转换为密文或将密文转换为明文的算法中输入的参数。密钥分为对称密钥与非对称密钥,分别应用在对称加密和非对称加密上。
对称加密:对称加密又叫做私钥加密,即信息的发送方和接收方使用同一个密钥去加密和解密数据。对称加密的特点是算法公开、加密和解密速度快,适合于对大数据量进行加密,常见的对称加密算法有DES、3DES、TDEA、Blowfish、RC5和IDEA。
其加密过程如下:明文 + 加密算法 + 私钥 => 密文
解密过程如下: 密文 + 解密算法 + 私钥 => 明文
对称加密中用到的密钥叫做私钥,私钥表示个人私有的密钥,即该密钥不能被泄露。
其加密过程中的私钥与解密过程中用到的私钥是同一个密钥,这也是称加密之所以称之为“对称”的原因。由于对称加密的算法是公开的,所以一旦私钥被泄露,那么密文就很容易被破解,所以对称加密的缺点是密钥安全管理困难。
非对称加密:非对称加密也叫做公钥加密。非对称加密与对称加密相比,其安全性更好。对称加密的通信双方使用相同的密钥,如果一方的密钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对密钥,即公钥和私钥,且二者成对出现。私钥被自己保存,不能对外泄露。公钥指的是公共的密钥,任何人都可以获得该密钥。用公钥或私钥中的任何一个进行加密,用另一个进行解密。
被公钥加密过的密文只能被私钥解密,过程如下:
明文 + 加密算法 + 公钥 => 密文, 密文 + 解密算法 + 私钥 => 明文
被私钥加密过的密文只能被公钥解密,过程如下:
明文 + 加密算法 + 私钥 => 密文, 密文 + 解密算法 + 公钥 => 明文
由于加密和解密使用了两个不同的密钥,这就是非对称加密“非对称”的原因。
非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
在非对称加密中使用的主要算法有:RSA、Elgamal、Rabin、D-H、ECC(椭圆曲线加密算法)等。
服务器端的公钥和私钥,用来进行非对称加密
客户端生成的随机密钥,用来进行对称加密
一个HTTPS请求实际上包含了两次HTTP传输,可以细分为8步。
1.客户端向服务器发起HTTPS请求,连接到服务器的443端口
2.服务器端有一个密钥对,即公钥和私钥,是用来进行非对称加密使用的,服务器端保存着私钥,不能将其泄露,公钥可以发送给任何人。
3.服务器将自己的公钥发送给客户端。
4.客户端收到服务器端的证书之后,会对证书进行检查,验证其合法性,如果发现发现证书有问题,那么HTTPS传输就无法继续。严格的说,这里应该是验证服务器发送的数字证书的合法性,关于客户端如何验证数字证书的合法性,下文会进行说明。如果公钥合格,那么客户端会生成一个随机值,这个随机值就是用于进行对称加密的密钥,我们将该密钥称之为client key,即客户端密钥,这样在概念上和服务器端的密钥容易进行区分。然后用服务器的公钥对客户端密钥进行非对称加密,这样客户端密钥就变成密文了,至此,HTTPS中的第一次HTTP请求结束。
5.客户端会发起HTTPS中的第二个HTTP请求,将加密之后的客户端密钥发送给服务器。
6.服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后的明文就是客户端密钥,然后用客户端密钥对数据进行对称加密,这样数据就变成了密文。
7.然后服务器将加密后的密文发送给客户端。
8.客户端收到服务器发送来的密文,用客户端密钥对其进行对称解密,得到服务器发送的数据。这样HTTPS中的第二个HTTP请求结束,整个HTTPS传输完成。
优点
使用 HTTPS 协议可认证用户和服务器,确保数据发送到正确的客户机和服务器 ;
HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 HTTP 协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性 。
HTTPS 是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本 。
缺点
相同网络环境下,HTTPS 协议会使页面的加载时间延长近 50%,增加 10%到 20%的耗电。
HTTPS 协议还会影响缓存,增加数据开销和功耗 。
HTTPS 协议的安全是有范围 中间人攻击 伪造证书
libcurl是一个跨平台的网络协议库, 支持http, https, ftp, gopher, telnet, dict, file和dap协议。libcurl同样支持HTTPS证书授权, HTTP POST, HTTP PUT, FTP上传, HTTP基本表单上传, 代理, cookies和用户认证
https://download.csdn.net/download/m0_52983689/19420260
其实还有简单的办法: sudo apt install libssl-dev libcurl4 libcurl4-openssl-dev
然后自己 gcc xxx.c -lcurl
首先去上面的链接下载libcurl库, 之后移动到ubuntu上面
安装路径指令详解
–prefix: 指定安装路径
–host: 指定交叉编译
例如: ./configure --prefix=$PWD/_install --host=arm-linux(指定安装在当前路径下的_install文件夹, 指定交叉编译工具是arm-linux…)
调用curl_global_init()初始化libcurl
调用curl_easy_init()函数得到 easy interface型指针
调用curl_easy_setopt()设置传输选项
根据curl_easy_setopt()设置的传输选项,实现回调函数以完成用户特定任务
调用curl_easy_perform()函数完成传输任务
调用curl_easy_cleanup()释放内存
1、CURLcode curl_global_init(long flags);函数只能用一次。(其实在调用curl_global_cleanup 函数后仍然可再用)
如果这个函数在curl_easy_init函数调用时还没调用,它将由libcurl库自动调用,所以多线程下最好主动调用该函数以防止在线程中curl_easy_init时多次调用。
注意:虽然libcurl是线程安全的,但curl_global_init是不能保证线程安全的,所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。
参数:flags
CURL_GLOBAL_ALL //初始化所有的可能的调用。
CURL_GLOBAL_SSL //初始化支持 安全套接字层。
CURL_GLOBAL_WIN32 //初始化win32套接字库。
CURL_GLOBAL_NOTHING //没有额外的初始化。
2、void curl_global_cleanup(void);
结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数。
注意:虽然libcurl是线程安全的,但curl_global_cleanup是不能保证线程安全的,所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。
3、char *curl_version( );
打印当前libcurl库的版本。
4、CURL curl_easy_init( );
curl_easy_init用来初始化一个CURL的指针(有些像返回FILE类型的指针一样). 相应的在调用结束时要用curl_easy_cleanup函数清理.
一般curl_easy_init意味着一个会话的开始. 它会返回一个easy_handle(CURL对象), 一般都用在easy系列的函数中.
5、void curl_easy_cleanup(CURL *handle);
这个调用用来结束一个会话.与curl_easy_init配合着用.
参数:
CURL类型的指针.
6、CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
这个函数最重要了.几乎所有的curl 程序都要频繁的使用它.它告诉curl库.程序将有如何的行为. 比如要查看一个网页的html代码等.(这个函数有些像ioctl函数)参数:
1 CURL类型的指针
2 各种CURLoption类型的选项.(都在curl.h库里有定义,man 也可以查看到)
3 parameter 这个参数 既可以是个函数的指针,也可以是某个对象的指针,也可以是个long型的变量.它用什么这取决于第二个参数.
CURLoption 这个参数的取值很多.具体的可以查看man手册.
7、CURLcode curl_easy_perform(CURL *handle);
在初始化CURL类型的指针 以及curl_easy_setopt完成后调用. 就像字面的意思所说perform就像是个舞台.让我们设置的
option 运作起来.参数:
CURL类型的指针.
本节主要介绍curl_easy_setopt中跟http相关的参数。该函数是curl中非常重要的函数,curl所有设置都是在该函数中完成的,该函数的设置选项众多,注意本节的阐述的只是部分常见选项。
1、CURLOPT_URL
设置访问URL
2、CURLOPT_WRITEFUNCTION,CURLOPT_WRITEDATA
回调函数原型为:size_t function( void *ptr, size_t size, size_t nmemb, void *stream); 函数将在libcurl接收到数据后被调用,因此函数多做数据保存的功能,如处理下载文件。CURLOPT_WRITEDATA 用于表明CURLOPT_WRITEFUNCTION函数中的stream指针的来源。
如果你没有通过CURLOPT_WRITEFUNCTION属性给easy handle设置回调函数,libcurl会提供一个默认的回调函数,它只是简单的将接收到的数据打印到标准输出。你也可以通过 CURLOPT_WRITEDATA属性给默认回调函数传递一个已经打开的文件指针,用于将数据输出到文件里。
3、CURLOPT_HEADERFUNCTION,CURLOPT_HEADERDATA
回调函数原型为 size_t function( void *ptr, size_t size,size_t nmemb, void *stream); libcurl一旦接收到http 头部数据后将调用该函数。CURLOPT_WRITEDATA 传递指针给libcurl,该指针表明CURLOPT_HEADERFUNCTION 函数的stream指针的来源。
4、CURLOPT_READFUNCTION CURLOPT_READDATA
libCurl需要读取数据传递给远程主机时将调用CURLOPT_READFUNCTION指定的函数,函数原型是:size_t function(void *ptr, size_t size, size_t nmemb,void *stream). CURLOPT_READDATA 表明CURLOPT_READFUNCTION函数原型中的stream指针来源。
5、CURLOPT_NOPROGRESS,CURLOPT_PROGRESSFUNCTION,CURLOPT_PROGRESSDATA
跟数据传输进度相关的参数。CURLOPT_PROGRESSFUNCTION 指定的函数正常情况下每秒被libcurl调用一次,为了使CURLOPT_PROGRESSFUNCTION被调用,CURLOPT_NOPROGRESS必须被设置为false,CURLOPT_PROGRESSDATA指定的参数将作为CURLOPT_PROGRESSFUNCTION指定函数的第一个参数
6、CURLOPT_TIMEOUT,CURLOPT_CONNECTIONTIMEOUT:
CURLOPT_TIMEOUT 由于设置传输时间,CURLOPT_CONNECTIONTIMEOUT 设置连接等待时间
7、CURLOPT_FOLLOWLOCATION
设置重定位URL
8、CURLOPT_RANGE: CURLOPT_RESUME_FROM:
断点续传相关设置。CURLOPT_RANGE 指定char *参数传递给libcurl,用于指明http域的RANGE头域,例如:
表示头500个字节:bytes=0-499
表示第二个500字节:bytes=500-999
表示最后500个字节:bytes=-500
表示500字节以后的范围:bytes=500-
第一个和最后一个字节:bytes=0-0,-1
同时指定几个范围:bytes=500-600,601-999
CURLOPT_RESUME_FROM 传递一个long参数给libcurl,指定你希望开始传递的 偏移量。
该函数是完成curl_easy_setopt指定的所有选项,本节重点介绍curl_easy_perform的返回值。返回0意味一切ok,非0代表错误发生。主要错误码说明:
1、CURLE_OK
任务完成一切都好
2、CURLE_UNSUPPORTED_PROTOCOL
不支持的协议,由URL的头部指定
3、CURLE_COULDNT_CONNECT
不能连接到remote 主机或者代理
4、CURLE_REMOTE_ACCESS_DENIED
访问被拒绝
5、CURLE_HTTP_RETURNED_ERROR
Http返回错误
6、CURLE_READ_ERROR
读本地文件错误
要获取详细的错误描述字符串,可以通过const char *curl_easy_strerror(CURLcode errornum ) 这个函数取得.
下面展示一些 内联代码片
。
#include <stdio.h>
#include <curl/curl.h>
bool getUrl(char *filename)
{
CURL *curl;
CURLcode res;
FILE *fp;
if ((fp = fopen(filename, "w")) == NULL) // 返回结果用文件存储
return false;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: Agent-007");
curl = curl_easy_init(); // 初始化
if (curl)
{
//curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");// 代理
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 改协议头
curl_easy_setopt(curl, CURLOPT_URL,"http://www.baidu.com");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); //将返回的http头输出到fp指向的文件
curl_easy_setopt(curl, CURLOPT_HEADERDATA, fp); //将返回的html主体数据输出到fp指向的文件
res = curl_easy_perform(curl); // 执行
if (res != 0) {
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
fclose(fp);
return true;
}
}
bool postUrl(char *filename)
{
CURL *curl;
CURLcode res;
FILE *fp;
if ((fp = fopen(filename, "w")) == NULL)
return false;
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt"); // 指定cookie文件
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "&logintype=uid&u=xieyan&psw=xxx86"); // 指定post内容
//curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");
curl_easy_setopt(curl, CURLOPT_URL, " http://mail.sina.com.cn/cgi-bin/login.cgi "); // 指定url
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
fclose(fp);
return true;
}
int main(void)
{
getUrl("/tmp/get.html");
postUrl("/tmp/post.html");
}
首先进入curl包里面删除旧的_install包, 因为之前编译的包没用, 不支持https的访问, docs文件夹里面的INSTALL.md文件明确告诉我们如果想要支持SSL, 就要用./configure --with-ssl指令, 要有这个–with-ssl参数选项, 如果加了运行指令后出现configure: error: --with-ssl was given but OpenSSL could not be detected的提示错误, 两种情况, 一种是没有安装openSSL, 因为要驱动openSSL, 你得先有openSSL, 另一种是编译环境没有加, 默认路径是在/usr/local/ssl底下
HTTPS 协议是由 SSL+HTTP 协议构建的
要让curl支持http加密, 它有依赖库, 系统得先有SSL, 才能去支持SSL
wget, 一个小窍门, 让linux的开源工具去linux的源码下面去找
安装OpenSSL: wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz, 安装前提, 得先能上网, 不然会提示无法解析, 安装完后继续执行
相关博文: https://blog.csdn.net/weixin_38184741/article/details/86554438
避免在安装curl的时候要配置ssl的路径, 直接把ssl默认安装到系统路径底下去
解压, 进入openssl文件夹, 之后./config, make编译, sudo make install安装, 安装的时候记得要sudo, 默认是安装到/usr/local底下去, 因为在工作目录底下才有权限, 在/usr/local底下没有
编译安装最新的openssl1.1.1的时候报错:
openssl: /usr/lib/x86_64-linux-gnu/libssl.so.1.1: version OPENSSL_1_1_1’ not found (required by openssl)
主要是LD_LIBRARY_PATH这个环境变量没有指定导致openssl正在使用旧的系统OpenSSL库
解决方法:
$ echo "export LD_LIBRARY_PATH=/usr/local/lib" >> ~/.bashrc
$ export LD_LIBRARY_PATH=/usr/local/lib
上面操作放到树莓派上面都一样
回到curl文件夹, 重新编译libcurl, 系统现在已经有了ssl, 输入./configure --prefix=$PWD/_install --with-ssl, 之后make, 再之后make install
安装完之后, 重新编译文件, 这时候就能进行人脸识别了
编译文件时可能遇到的问题
gcc xxx.c -I ./curl-7.71.1/_install/include/ -L ./curl-7.71.1/_install/lib/ -lcurl -lssl -lcrypto, 加上ssl和crypto的库即可, 因为你用到了openssl中的函数, 但是你的代码中有没有该函数的实现, 只好链接openssl提供的链接库
下面展示一些 内联代码片
。
/*人脸识别代码, 人脸是识别有两种方式, 一种是base64流, 一种是file文档, 这里我用到的是base64流*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <curl/curl.h>
#define true 1
#define false 0
typedef unsigned int bool;
char buf[1024] = {'\0'};
size_t readData( void *ptr, size_t size, size_t nmemb, void *stream)
{
strncpy(buf, ptr, 1024); //将运行完后的结果复制到buf中
//printf("==============================getData=============================\n");
//printf("%s\n",buf);
}
char *getPicBase64File(char *picFile)
{
char cmd[32] = {'\0'};
sprintf(cmd, "base64 %s > tmpFile", picFile); //base64指令, 运行完后将流放进tmpFile文件里
system(cmd); //运行指令
int fd = open("./tmpFile",O_RDWR); //打开流文件
int fileLen = lseek(fd, 0, SEEK_END); //计算文件大小
lseek(fd, 0, SEEK_SET); //计算完文件大小后, 光标的位置在最后, 我们接下来要做读操作, 所以把光标移到开头
char *bufPic = (char *)malloc(fileLen); //定义一个跟流文件同样大小的字符串
memset(bufPic, 0, fileLen);
read(fd, bufPic, fileLen); //将文件里面的内容写入新创建的字符串里
close(fd); //关闭文件
system("rm ./tmpFile"); //删除tmpFile文件, 用完就删除
return bufPic;
}
bool postUrl()
{
CURL *curl;
CURLcode res;
char *postString;
/*base64流有六个参数, 详细可以见翔云人脸识别API文档*/
char img1[32] = {'\0'}; //上传的文件(base64流, 用base64 ***.jpg生成)
char img2[32] = {'\0'}; //上传的文件(base64流, 用base64 ***.jpg生成)
char *key = ""; //ocrkey, 人脸识别需要用到的参数之一, 在翔云个人中心可以查到(我用的是翔云), 进行识别前记得先购买, 一毛一百次
char *secret = ""; //ocrsecret, 人脸识别需要用到的参数之一, 在翔云个人中心可以查到, 进行识别前记得先购买, 一毛一百次
(我用的是翔云)
int typeId = 21; //对应的类型, 人脸识别对应的id是21
char *format = "xml"; //返回格式有两种, 一种是xml, 一种是json, 我们用的是xml
char *bufPic1 = getPicBase64File("./reba1.jpg"); //调用函数, 获取图片的base64流
char *bufPic2 = getPicBase64File("./reba2.jpg"); //调用函数, 获取图片的base64流
int len = strlen(key)+strlen(secret)+strlen(bufPic1)+strlen(bufPic2)+128; //算出六个参数所需要用到的空间大小
postString = (char *)malloc(len);
memset(postString, 0, len);
sprintf(postString, "&img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s",
bufPic1,bufPic2,key,secret,21,format); //封装post内容
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postString); // 指定post内容
curl_easy_setopt(curl, CURLOPT_URL, "https://netocr.com/api/faceliu.do"); // 指定url
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readData); //将返回的html主体数据用函数读出
res = curl_easy_perform(curl);
printf("OK:%d\n",res);
/*找出返回数据的内容中是否带有是或否, 进行判断*/
if(strstr(buf,"是") != NULL){
printf("the same person\n"); //是同一个人
}else{
printf("diff person\n"); //不是同一个人
}
curl_easy_cleanup(curl);
}
return true;
}
int main(void)
{
postUrl(); //post请求
}
车牌识别的代码跟上面人脸识别的代码一样, 只需要更换成对应参数即可实现
下面展示一些 内联代码片
。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <curl/curl.h>
#define true 1
#define false 0
typedef unsigned int bool;
char buf[1024] = {'\0'};
size_t readData( void *ptr, size_t size, size_t nmemb, void *stream)
{
strncpy(buf, ptr, 1024); //将运行完后的结果复制到buf中
printf("==============================getData=============================\n");
printf("%s\n",buf);
}
char *getPicBase64File(char *picFile)
{
char cmd[128] = {'\0'};
sprintf(cmd, "base64 %s > tmpFile", picFile); //base64指令, 运行完后将流放进tmpFile文件里
system(cmd); //运行指令
int fd = open("./tmpFile",O_RDWR); //打开流文件
int fileLen = lseek(fd, 0, SEEK_END); //计算文件大小
lseek(fd, 0, SEEK_SET); //计算完文件大小后, 光标的位置在最后, 我们接下来要做读操作, 所以把光标移到开头
char *bufPic = (char *)malloc(fileLen); //定义一个跟流文件同样大小的字符串
memset(bufPic, 0, fileLen);
read(fd, bufPic, fileLen); //将文件里面的内容写入新创建的字符串里
close(fd); //关闭文件
system("rm ./tmpFile"); //删除tmpFile文件
return bufPic;
}
bool postUrl()
{
CURL *curl;
CURLcode res;
char *postString;
/*车牌识别有五个参数, 详细可以见翔云人脸识别API文档*/
char *key = ""; //ocrkey, 车牌识别需要用到的参数之一, 在翔云个人中心可以查到(我用的是翔云), 进行识别前记得先购买, 一毛一百次
char *secret = ""; //ocrsecret, 车牌识别需要用到的参数之一, 在翔云个人中心可以查到, 进行识别前记得先购买, 一毛一百次
(我用的是翔云)
int typeId = 19; //对应的类型, 车牌识别对应的id是19
char *format = "xml"; //返回格式有两种, 一种是xml, 一种是json, 我们用的是xml
char *bufPic = getPicBase64File("./car.jpg"); //调用函数, 获取图片的base64流
int len = strlen(key)+strlen(secret)+strlen(bufPic)+128; //算出五个参数所需要用到的空间大小
postString = (char *)malloc(len);
memset(postString, 0, len);
sprintf(postString, "&img=%s&key=%s&secret=%s&typeId=%d&format=%s",
bufPic,key,secret,typeId,format); //封装post内容
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postString); // 指定post内容
curl_easy_setopt(curl, CURLOPT_URL, "https://netocr.com/api/recogliu.do"); // 指定url
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readData); //将返回的html主体数据用函数读出
res = curl_easy_perform(curl);
printf("OK:%d\n",res);
/*找出返回数据的内容中是否带有是或否, 进行判断*/
if(strstr(buf,"是") != NULL){
//printf("the same person\n");
}else{
//printf("diff person\n");
}
curl_easy_cleanup(curl);
}
return true;
}
int main(void)
{
postUrl(); //post请求
}
获取车牌号代码
下面展示一些 内联代码片
。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i = 0;
char *str = (char *)malloc(12);
memset(str, 0, 12);
int fd = open("./carfile",O_RDWR);
int len = lseek(fd, 0, SEEK_END);
char *buf = (char *)malloc(len);
memset(buf, 0, len);
lseek(fd, 0, SEEK_SET);
read(fd, buf, len);
close(fd);
/*返回的数据里面找到车牌号*/
if(strstr(buf,"车牌号") != NULL){
char *p = strstr(buf,"车牌号"); //strstr函数的作用是如果主字符串里包含子字符串, 它的返回值就是出现子字符串的位置
p = p+strlen("车牌号"); //把光标移到号字后, 没移之前的光标在车前面
p = p+11; //地址移位
for(i=0; i<9; i++){
str[i] = *p++;
}
printf("get data:%s\n",str);
}
return 0;
}