树莓派摄像头,七层网络模型,协议相关,libcurl库相关,人脸、车牌识别
下载mjpg-streamer
git clone https://github.com/jacksonliam/mjpg-streamer.git
安装需要的库
sudo apt-get install libjpeg8-dev
sudo apt-get install imagemagick
sudo apt-get install libv4l-dev
sudo apt-get install cmake
进入下载好的mjpg-streamer文件夹中
make all
sudo make install
因为是bullseye版的系统,所以没有input_raspicam.so文件
(若是stretch版本的,需要进入到start.sh脚本中,将
./mjpg_streamer -i "./input_uvc.so" -o "./output_http.so -w ./www"
//修改为
./mjpg_streamer -i "./input_raspicam.so" -o "./output_http.so -w ./www"
sudo raspi-config
选择interfacing Options 开启摄像头
开启摄像头之后回到mjpg-streamer文件夹下,运行start.sh脚本
./start.sh
之后在浏览器中输入
http://树莓派IP:8080
回车点击Stream,即可看到摄像头显示的画面
7 应用层 例如HTTP、HTTPS、SMTP、SNMP、FTP、Telnet、SIP、SSH、NFS、RTSP、XMPP、Whois、ENRP
6 表示层 例如XDR、ASN.1、SMB、AFP、NCP
5 会话层 例如ASAP、TLS、SSH、ISO 8327 / CCITT X.225、RPC、NetBIOS、ASP、Winsock、BSD sockets
4 传输层 例如TCP、UDP、RTP、SCTP、SPX、ATP、IL
3 网络层 例如IP、ICMP、IGMP、IPX、BGP、OSPF、RIP、IGRP、EIGRP、ARP、RARP、 X.25
2 数据链路层 例如以太网、令牌环、HDLC、帧中继、ISDN、ATM、IEEE 802.11、FDDI、PPP
1 物理层 例如线路、无线电、光纤、信鸽
物理层:网卡,网线,集线器,中继器,调制解调器
数据链路层:网桥,交换机
网络层:路由器
网关工作在第四层传输层及其以上
解决两个硬件之间怎么通信的问题。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。
在计算机网络中由于各种干扰的存在,物理链路是不可靠的。该层的主要功能就是:通过各种控制协议,将有差错的物理信道变为无差错的、能可靠传输数据帧的数据链路。
它的具体工作是接收来自物理层的位流形式的数据,并封装成帧,传送到上一层;同样,也将来自上层的数据帧,拆装为位流形式的数据转发到物理层。这一层的数据叫做帧。
数据链路层是解决同一网络内节点之间的通信。
计算机网络中如果有多台计算机,怎么找到要发的那台?如果中间有多个节点,怎么选择路径?这就是路由要做的事。
该层的主要任务就是:通过路由选择算法,为报文(该层的数据单位,由上一层数据打包而来)通过通信子网选择最适当的路径。这一层定义的是IP地址,通过IP地址寻址,所以产生了IP协议。
网络层主要解决不同子网间的通信。
当发送大量数据时,很可能会出现丢包的情况,另一台电脑要告诉是否完整接收到全部的包。如果缺了,就告诉丢了哪些包,然后再发一次,直至全部接收为止。
简单来说,传输层的主要功能就是:监控数据传输服务的质量,保证报文的正确传输。
虽然已经可以实现给正确的计算机,发送正确的封装过后的信息了。但我们总不可能每次都要调用传输层协议去打包,然后再调用IP协议去找路由,所以我们要建立一个自动收发包,自动寻址的功能。于是会话层出现了:它的作用就是建立和管理应用程序之间的通信
组织和协调两个会话进程之间的通信,并对数据交换进行管理
表示层负责数据格式的转换,将应用处理的信息转换为适合网络传输的格式,或者将来自下一层的数据转换为上层能处理的格式。
应用层是计算机用户,以及各种应用程序和网络之间的接口,其功能是直接向用户提供服务,完成用户希望在网络上完成的各种工作。
OSI下3层的主要任务是数据通信,上3层的任务是数据处理。而传输层(Transport Layer)是OSI模型的第4层。因此该层是通信子网和资源子网的接口和桥梁,起到承上启下的作用。
由于OSI是一个理想的模型,因此一般网络系统只涉及其中的几层,很少有系统能够具有所有的7层,并完全遵循它的规定。在7层模型中,每一层都提供一个特殊的网络功能。从网络功能的角度观察:下面4层(物理层、数据链路层、网络层和传输层)主要提供数据传输和交换功能,即以节点到节点之间的通信为主;第4层作为上下两部分的桥梁,是整个网络体系结构中最关键的部分;而上3层(会话层、表示层和应用层)则以提供用户与应用程序之间的信息和数据处理功能为主。简言之,下4层主要完成通信子网的功能,上3层主要完成资源子网的功能。
在 TCP/IP 协议中,TCP 协议提供可靠的连接服务,采用三次握手建立一个连接。
三次握手的过程:
第一步: A 的 TCP 向 B 发出连接请求报文段,其首部中的同步位 SYN = 1,并选择序号 seq = x,表明传送数据时的第一个数据字节的序号是 x。
SYN=1, ACK= 0 连接请求
第二步 B 的 TCP 收到连接请求报文段后,如同意,则发回确认。B 在确认报文段中应使 SYN = 1,使 ACK = 1,其确认号ack = x + 1,自己选择的序号 seq = y。
SYN=1, ACK=1 请求确认
第三步 A 收到此报文段后向 B 给出确认,其 ACK = 1,确认号 ack = y + 1。A 的 TCP 通知上层应用进程,连接已经建立。B 的 TCP 收到主机 A 的确认后,也通知其上层应用进程:TCP 连接已经建立。
SYN=0, ACK=1 连接确认
TCP为什么需要进行三次握手?
为了保证服务端能收接受到客户端的信息并能做出正确的应答而进行前两次(第一次和第二次)握手,为了保证客户端能够接收到服务端的信息并能做出正确的应答而进行后两次(第二次和第三次)握手。
第一步:现在 A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP 连接。A 把连接释放报文段首部的 FIN = 1,其序号seq = u,等待 B 的确认。
FIN=1,ACK=0 断开请求
第二步 B 发出确认,确认号 ack = u + 1,而这个报文段自己的序号 seq = v。 TCP 服务器进程通知高层应用进程。从 A 到 B 这个方向的连接就释放了,TCP 连接处于半关闭状态。 B 若发送数据,A 仍要接收
FIN=0,ACK=1 断开确认
A收到B的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待B发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
第三步 B将最后的数据发送完毕后,就向A发送连接释放报文,确认号ack=u+1,由于在半关闭状态,B很可能又发送了一些数据,假定此时的序列号为seq=w,此时,A就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
FIN=1,ACK=1 请求确认
第四步 A 收到连接释放报文段后,必须发出确认。在确认报文段中 ACK = 1,确认号 ack = w + 1,自己的序号 seq = u + 1。此时,A就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当A撤销相应的TCB后,才进入CLOSED状态。
FIN=0,ACK=1 断开确认
B只要收到了A发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,B结束TCP连接的时间要比A早一些。
为什么连接的时候是三次握手,关闭的时候却是四次握手?
Server端可能在忙与其他Client的数据传输,要等Server端完成自己的工作在回复Client端,和它确认断开;因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。**Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。**所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
如果已经建立了连接,但是客户端突然出现故障了怎么办?
答1:保活计时器,每隔一段时间会进行检查,检查多次了之后还没有连接上的话就会关闭连接。
答2:TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
tcp和http
HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。
HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。
由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即时不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。
socket和tcp
套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。
Socket是对TCP/IP协议的封装和应用(程序员层面上)。Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。实际上,Socket跟TCP/IP协议没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以说,Socket的出现 只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口,比如create、 listen、connect、accept、send、read和write等等。
我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如
果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP、FTP、TELNET等。
socket和http
HTTP是短连接,Socket(基于TCP协议的)是长连接。尽管HTTP1.1开始支持持久连接,但仍无法保证始终连接。而Socket连接一旦建立TCP三次握手,除非一方主动断开,否则连接状态一直保持。
HTTP连接服务端无法主动发消息,Socket连接双方请求的发送先后限制。这点就比较重要了,因为它将决定二者分别适合应用在什么场景下。HTTP采用“请求-响应”机制,在客户端还没发送消息给服务端前,服务端无法推送消息给客户端。必须满足客户端发送消息在前,服务端回复在后。Socket连接双方,一方随时可以向另一方喊话。
由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。
而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。
http协议
http协议的报文传输的是ASCII码,是建立在TCP/IP协议之上应用层协议,默认端口为80。http协议的的特点是无状态,短连接。
http协议的请求包括请求行、请求头、请求体。
请求行:包括三个信息请求方式,url(网址),http协议版本
请求方式分为GET 请求和POST请求。
请求头:浏览器向服务器发送一些状态数据,标识数据等等
请求体:POST形式发送的表单数据!
GET请求,没有请求主体部分!get数据是在请求行中的url上进行传递的!
http协议的响应包括响应行、响应头、响应体。
响应行:协议版本、状态码、状态消息。
响应头:包括响应主体数据的格式、 响应主体数据的长度、响应的时间等等。
响应主体:主要的响应数据,在浏览器的主体区域显示的数据都是相应主体。
状态码 :以5开头,服务器端出现问题,如500 服务器内部错误
以4开头,客户端出现问题,如404 请求的页面没有找到,403 没有权限
以2开头,成功状态码,如200 请求成功
GET 请求和POST请求的区别
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(返回数据)。
https协议
http协议是明文传输的,因此很容易被截取和解析,泄漏个人数据。https协议是在http和tcp之间多添加了一层,进行身份验证和数据加密。
明文: 明文指的是未被加密过的原始数据。
密文:明文被某种加密算法加密之后,会变成密文,从而确保原始数据的安全。
密钥:密钥是一种参数,它是在明文转换为密文或将密文转换为明文的算法中输入的参数。密钥分为对称密钥与非对称密钥,分别应用在对称加密和非对称加密上。
对称加密:对称加密又叫做私钥加密,即信息的发送方和接收方使用同一个密钥去加密和解密数据。对称加密的特点是算法公开、加密和解密速度快,适合于对大数据量进行加密,常见的对称加密算法有DES、3DES、TDEA、Blowfish、RC5和IDEA。
其加密过程如下:明文 + 加密算法 + 私钥 => 密文
解密过程如下: 密文 + 解密算法 + 私钥 => 明文
对称加密中用到的密钥叫做私钥,私钥表示个人私有的密钥,即该密钥不能被泄露。
对称加密的缺点是密钥安全管理困难。
非对称加密:非对称加密也叫做公钥加密。非对称加密与对称加密相比,其安全性更好。对称加密的通信双方使用相同的密钥,如果一方的密钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对密钥,即公钥和私钥,且二者成对出现。私钥被自己保存,不能对外泄露。公钥指的是公共的密钥,任何人都可以获得该密钥。用公钥或私钥中的任何一个进行加密,用另一个进行解密。在非对称加密中使用的主要算法有:RSA、Elgamal、Rabin、D-H、ECC等。
被公钥加密过的密文只能被私钥解密,过程如下:
明文 + 加密算法 + 公钥 => 密文, 密文 + 解密算法 + 私钥 => 明文
被私钥加密过的密文只能被公钥解密,过程如下:
明文 + 加密算法 + 私钥 => 密文, 密文 + 解密算法 + 公钥 => 明文
非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
服务器端的公钥和私钥,用来进行非对称加密
客户端生成的随机密钥,用来进行对称加密
安装支持https的libcurl库
sudo apt install libssl-dev libcurl4-openssl-dev
libcurl库函数简介
调用curl_global_init()初始化libcurl
CURLcode curl_global_init(long flags) //flags一般为CURL_GLOBAL_ALL 初始化所有可能的调用
//如果此函数返回非零,则出现错误,无法使用其他curl函数。
调用curl_easy_init()函数返回CURL简易句柄
CURL *curl_easy_init( ) //相应的在调用结束时要用curl_easy_cleanup函数清理.
//如果没有调用curl_global_init,curl_easy_init会自动执行此操作,在多线程情况下是不安全的,所以强烈建议正确调用curl_global_init
//如果此函数返回NULL,则出现错误,无法使用其他curl函数。
调用curl_easy_setopt()设置传输选项
CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter)
调用curl_easy_perform()函数完成传输任务
CURLcode curl_easy_perform(CURL * easy_handle) //返回0表示一切正常,非零表示发生错误,且不同的返回值对应不同的错误类型
//在curl_easy_init之后调用此函数并进行所有curl_easy_setopt调用,并将按照选项中的描述执行传输
调用curl_easy_cleanup()释放内存
void curl_easy_cleanup(CURL *handle);
释放 curl_global_init()已经获得的所有资源
void curl_global_cleanup(void);
对于curl_easy_setopt函数部分选项
CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter)
//返回值为0表示选项设置正确,非零发生错误
//第3个参数的值根据第2个参数不同的值而不同
将CURLoption option值设为
CURLOPT_URL:
这个选项后面接实际要放访问Http服务器的URL地址
CURLOPT_WRITEFUNCTION:
使用该选项时,要求第3个参数中的回调函数必须是下面的函数原型:
size_t function( char *ptr, size_t size, size_t nmemb, void *userdata);
在启动会话时,一旦检测到有需要接收的数据时,回调函数被调用,接收到的数据保存在 ptr 所指向的区域,函数多做数据保存的功能,如处理下载文件
ptr 所指向的数据大小由 size 和 nmemb 的乘积获得。
CURLOPT_WRITEDATA:
使用该选项时,函数的第 3 个参数必须是个 FILE 指针,函数会将接收到的数据自动的写到这个 FILE 指针所指向的文件流中。
CURLOPT_HEADERFUNCTION
CURLOPT_HEADERDATA
类似,libcurl一旦接收到http头部数据后将调用该函数
CURLOPT_READFUNCTION
CURLOPT_READDATA
类似,libCurl需要读取数据传递给远程主机时将调用CURLOPT_READFUNCTION指定的函数
CURLOPT_POSTFIELDS:
传递一个作为HTTP “POST”操作的所有数据的字符串
基本的http GET/POST操作
#include
#include
#define true 1
#define false 0
typedef int bool;
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");
}
人脸识别
#include
#include
#include
#include
#include
#include
#include
#include
#define true 1
#define false 0
typedef int bool;
size_t readData( void *ptr, size_t size, size_t nmemb, void *stream)
{
/* char buf[10240] = {'\0'};
strncpy(buf,ptr,10240);
printf("read data==========\n");
printf("%s\n",buf);*/
if(strstr(ptr,"是")) printf("same person\n");
else printf("different person\n");
}
char *readbase64(char *fileName)
{
char cmd[128] = {'\0'};
sprintf(cmd,"base64 %s > ./tmp",fileName);
system(cmd);
int fd = open("./tmp",O_RDWR);
int size = lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
char *buf = (char *)malloc(size +1);
memset(buf,'\0',size+1);
read(fd,buf,size +1);
close(fd);
system("rm ./tmp");
return buf;
}
bool postUrl()
{
char *image1 = readbase64("~/Desktop/renLian1.jpeg");
char *image2 = readbase64("~/Desktop/renLian2.jpeg");
char *key = "J8ZkUw6tgr7AN3RCtSZnsX";
char *secret = "4772d8017a8d439fa581d4c269a6f613";
int typeId = 21;
char *format = "xml";
int len = strlen(key) + strlen(secret) + strlen(format) + strlen(image1) + strlen(image2) + 128;
char *postString = (char *)malloc(len);
memset(postString,'\0',len);
sprintf(postString,"&img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s",
image1,image2,key,secret,typeId,format);
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt"); // 指定cookie文件
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_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readData);
res = curl_easy_perform(curl);
printf("%d\n",res);
curl_easy_cleanup(curl);
}
return true;
}
int main(void)
{
postUrl();
}
车牌识别
#include
#include
#include
#include
#include
#include
#include
#include
#define true 1
#define false 0
typedef int bool;
size_t readData( void *ptr, size_t size, size_t nmemb, void *stream)
{
char buf[10240] = {'\0'};
strncpy(buf,ptr,10240);
printf("read data==========\n");
printf("%s\n",buf);
/* if(strstr(ptr,"是")) printf("same person\n");
else printf("different person\n");*/
}
char *readbase64(char *fileName)
{
char cmd[128] = {'\0'};
sprintf(cmd,"base64 %s > ./tmp",fileName);
system(cmd);
int fd = open("./tmp",O_RDWR);
int size = lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
char *buf = (char *)malloc(size +1);
memset(buf,'\0',size+1);
read(fd,buf,size +1);
close(fd);
system("rm ./tmp");
return buf;
}
bool postUrl()
{
char *image1 = readbase64("~/Desktop/car.jpeg");
char *key = "J8ZkUw6tgr7AN3RCtSZnsX";
char *secret = "4772d8017a8d439fa581d4c269a6f613";
int typeId = 19;
char *format = "xml";
int len = strlen(key) + strlen(secret) + strlen(format) + strlen(image1) + 128;
char *postString = (char *)malloc(len);
memset(postString,'\0',len);
sprintf(postString,"&img=%s&key=%s&secret=%s&typeId=%d&format=%s",
image1,key,secret,typeId,format);
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt"); // 指定cookie文件
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_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readData);
res = curl_easy_perform(curl);
printf("%d\n",res);
curl_easy_cleanup(curl);
}
return true;
}
int main(void)
{
postUrl();
}
1.安装libv4l-dev时报错
这个是因为树莓派换源时出现问题,树莓派换源要注意关键字
原来树莓派的系统版本为bullseye,所以换源后的版本也必须为bullseye
2.包里的INSTALL文件,是说该文件如何去编译,一般打开包就能找到,或者在包里的docs文件夹下
3..gz .bz2 .xz 都是压缩文件,只不过压缩的算法不同,都可以用tar工具解压
.asc文件是对该类型压缩包的校验文件
>tar xvf code.tar.
>tar xvf code.tar.gz
>tar xvf code.tar.bz2 //xvf可以解压.tar .tar.gz .tar.bz2
>tar cvf code.tar /home/abc/code/ //将文件打包为.tar
>tar cvzf code.tar.gz /home/abc/code //将文件压缩打包为 .tar.gz
>tar cvfj code.tar.bz2 /home/abc/code/ //将文件压缩打包为 .tar.bz2
//f 这个参数确实是必选的,要不你就找不到你的tar文件
//v 也很重要,通常就能看出详细信息
curl -V
curl –version
// 在curl_easy_perform之前加上这句
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0) //关闭检查
6.将当前目录下的xxx图片的base64流数据保存到当前目录下的tmp文件中
base64 ./xxx.jpg > ./tmp