当前位置:网站首页>利用C语言实现URL解析的基本方法之优秀
利用C语言实现URL解析的基本方法之优秀
2022-07-27 12:53:00 【ST小智】
今天主要来学习一下,如何利用URL,实现对应的解析过程。
第一:URL是什么
URL代表着是统一资源定位符(UniformResourceLocator)。
作用是为了告诉使用者 某个资源在 Web 上的地址。
这个资源可以是一个 HTML 页面,一个 CSS 文档,一幅图像或一个猫片等等。
比如:
用HTTP协议访问Web服务器:

用FTP协议下载和上传文件时

读取客户端计算机本地文件时

这里面细分,又可以分为好几个部分。
1、协议
尽管 URL 有各种不同的写法, 但它们有一个共同点, 开头部分的内容必须是协议类型,
可以是http、ftp、mailto或者https,这部分文字都表示浏览器应当使用的访问方法。会用//为分隔符。决定了后面部分的写法, 因此并不会造成混乱。
2、用户名/密码
用户名密码通常可以省略。
3、域名
域名是www.gitee.com,在发送请求前,会向DNS服务器解析IP。如果已经知道ip,还可以跳过DNS解析那一步,直接把IP当做域名部分使用。
4、端口
域名后面有些时候会带有端口,和域名之间用:分隔,端口不是一个URL的必须的部分。当网址为http://时,默认端口为80, https://时,默认端口是443, ftp://时,默认端口是21。
5、文件路径/文件名
从域名的第一个/开始到最后一个/为止,是虚拟目录的部分。虚拟目录也不是URL必须的部分,上述实例http协议url中的虚拟目录是/yikoulinux/chat/blob/master/
从域名最后一个/开始到?为止,是文件名部分;如果没有?,则是从域名最后一个/开始到#为止,是文件名部分;如果没有?和#,那么就从域名的最后一个/从开始到结束,都是文件名部分。
比如前面的http url实例,其中文件chat.h在gitee服务器/yikoulinux/chat/blob/master/下:

文件名也不是一个URL的必须部分。
文件名省略情况如下:
1.http://www.gitee.com/dir/
我们可以这样理解, 以“/” 结尾代表 /dir/ 后面本来应该有的文件名被省略了。根据 URL 的规则, 文件名可以像前面这样省略。不过, 没有文件名, 服务器怎么知道要访问哪个文件呢?其实, 我们会在服务器上事先设置好文件名省略时要访问的默认文件名。这个设置根据服务器不同而不同, 大多数情况下是 index.html 或者 default.htm 之类的文件名。
因此, 像前面这样省略文件名时, 服务器就会访问 /dir/index.html或者 /dir/default.htm[由web服务器配置]。
2.http://www.gitee.com/ 这个 URL 也是以“/” 结尾的, 也就是说它表示访问一个名叫“/” 的目录 。而且, 由于省略了文件名, 所以结果就是访问 /index.html 或者/default.htm 这样的文件了。
3.http://www.gitee.com 这次连结尾的“/” 都省略了。像这样连目录名都省略时, 真不知道到底在请求哪个文件了, 实在有些过分。不过, 这种写法也是允许的。当没有路径名时, 就代表访问根目录下事先设置的默认文件 , 也就是 /index.html 或者 /default.htm 这些文件, 这样就不会发生混乱了。
4.http://www.gitee.com/yikoupeng
一般来说, 这种情况会按照下面的惯例进行处理:如果Web 服务器上存在名为 yikoupeng的文件, 则将 yikoupeng作为文件名来处 理;如果存在名为 yikoupeng的目录, 则将 yikoupeng作为目录名来处理 。
第二:通过一个例子实现解析
编写一个简单的用于解析url的小例子,最终目标是解析出URL中所有的数据信息。

第三:库函数
用到的几个库函数如下:
1. strncasecmp
头文件
#include<string.h>
函数定义
int strncasecmp(const char *s1,const char *s2,size_t n);
函数说明
用来比较参数s1和s2字符串前n个字符,比较时会自动忽略大小写的差异。
返回值
若参数s1和s2 字符串相同则返回0。
s1 若大于s2则返回大于0的值,
s1若小于s2则返回小于0 的值。
2. strstr
头文件
#include<string.h>
函数定义
char *strstr( const char* str, const char* substr );
函数说明
查找 substr 所指的空终止字节字符串在 str 所指的空终止字节字符串中的首次出现。不比较空终止字符。
若 str 或 substr 不是指向空终止字节字符串的指针,则行为未定义。
参数
str :指向要检验的空终止字节字符串的指针
substr :指向要查找的空终止字节字符串的指针
返回值
指向于 str 中找到的子串首字符的指针,或若找不到该子串则为空指针。若 substr 指向空字符串,则返回 str 。
3. strtok
函数定义
char *strtok(char *str, const char *delim)
功能
分解字符串 str 为一组字符串,delim 为分隔符
参数
str -- 要被分解成一组小字符串的字符串。
delim -- 包含分隔符的 C 字符串。
返回值
该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。
4. strncpy
函数说明
char *strncpy(char *dest, const char *src, size_t n)
功能
将src指向的字符串拷贝到dest执行的内存中,最多拷贝n个字符
参数
dest -- 指向用于存储复制内容的目标数组。
src -- 要复制的字符串。
n -- 要从源中复制的字符数。
返回值
该函数返回最终复制的字符串。
5. inet_pton/inet_ntop
头文件
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
函数声明
#include <arpe/inet.h>
int inet_pton(int family, const char *strptr, void *addrptr);
功能:
将点分十进制的ip地址转化为用于网络传输的数值格式
对于IPv4地址和IPv6地址都适用
参数
family:协议类型既可以是AF_INET(ipv4)也可以是AF_INET6(ipv6)。如果,以不被支持的地址族作为family参数,这两个函数都返回一个错误,并将errno置为EAFNOSUPPORT.
strptr:指向点分十进制的IP地址字符串,比如"192.168.1.1"
addrptr:转换结果存放在addrptr中,比如"192.168.1.1"转换为:0xC0A80101
addrptr类型为:struct in_addr
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};
返回值
若成功则为1,若输入不是有效的表达式则为0,
若出错则为-1
const char * inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
功能
将数值格式转化为点分十进制的ip地址格式,从数值格式(addrptr)转换到表达式(strptr),
返回值
若成功则为指向结构的指针,若出错则为NULL
6. gethostbyname
函数的定义
#include <netdb.h>
struct hostent * gethostbyname(const char * hostname);
功能
解析hostname指向的域名,该函数会将该域名封装到DNS协议包中,发送给DNS服务器,DNS服务器会将该域名对应的地址返回,存储在struct hostent中
参数
hostname :存储域名对应的字符串。
返回值
若成功则为非空指针,若出错则为NULL且设置h_errno
返回的指针类型为:
struct hostent{
char *h_name; //official name
char **h_aliases; //alias list
int h_addrtype; //host address type
int h_length; //address lenght
char **h_addr_list; //address list
}
DNS服务器返回的地址就存储在该结构体中
第四:自定义结构
结构体用于存放需要解析的协议和端口号
struct pro_port{
char pro_s[32];
unsigned short port;
};
目前本例子只解析以下集中协议,读者需要支持其他协议可以按照该格式增加对应信息即可
#define HEAD_FTP_P "ftp://"
#define HEAD_FTPS_P "ftps://"
#define HEAD_FTPES_P "ftpes://"
#define HEAD_HTTP_P "http://"
#define HEAD_HTTPS_P "https://"
#define PORT_FTP 21
#define PORT_FTPS_I 990 //implicit
#define PORT_FTPS_E 21 //explicit
#define PORT_HTTP 80
#define PORT_HTTPS 443
struct pro_port g_pro_port[]={
{HEAD_FTP_P,PORT_FTP},
{HEAD_FTPS_P,PORT_FTPS_I},
{HEAD_FTPES_P,PORT_FTPS_E},
{HEAD_HTTP_P,PORT_HTTP},
{HEAD_HTTPS_P,PORT_HTTPS},
};
第五:程序流程图

程序流程相对来说,比较简单,主函数功能说明如下:
1. parse_url()
int parse_url(char *raw_url,URL_RESULT_T *result)
参数:
raw_url:指向一个url字符串,比如:ftp://peng:[email protected]/dir/index.html
result :url解析后的结果存放在该结构体中
结构体类型定义如下:
typedef struct
{
char user[MAX_USER_LEN];
char pass[MAX_PASS_LEN];
char domain[INET_DOMAINSTRLEN];//域名
char svr_dir[MAX_PATH_FILE_LEN]; //文件路径
char svr_ip[MAX_IP_STR_LEN];
int port;
}URL_RESULT_T;
功能:
解析url字符串,并将解析结果存放在result中
返回值;
成功返回 URL_OK
失败返回 URL_ERROR
2. void remove_quotation_mark()
void remove_quotation_mark(char *input)
参数
input:字符串
功能
去掉字符串中的双引号 \"
返回值
无
3. parse_domain_dir
int parse_domain_dir(char *url,URL_RESULT_T *result)
参数
url:执行去掉协议头的url字符串,比如:peng:[email protected]/dir/index.html
result :url解析后的结果存放在该结构体中
功能
解析出url中用户名、密码、域名/ip、文件路径等信息
返回值
成功:URL_OK
失败:URL_ERROR
4. check_is_ipv4()
int check_is_ipv4(char *domain)
参数
domain:指向一个域名或者IP地址点分十进制字符串,最大长度为:MAX_URL_LEN
功能
判断domain中存放的是不是合法的IP地址
返回值
1:是IP地址
-1:不是IP地址
5、dns_resoulve()
int dns_resoulve(char *svr_ip,const char *domain)
参数
svr_ip:存放DNS协议解析过的域名对应的IP地址点分十进制字符串
domain:域名字符串
功能
将domain中的域名,通过DNS协议解析成对应的IP地址
返回值
成功:URL_OK
失败:URL_ERROR
第六:运行
测试程序
void main(void)
{
int ret;
char url_str[256]="ftp://peng:[email protected]/dir/index.html";
parse_url(url_str,&url_result_t);
ret = check_is_ipv4(url_result_t.domain);
if(ret != 1)
{
//dns
dns_resoulve(url_result_t.svr_ip,url_result_t.domain);
}
printf("\n-------------result---------------\n");
printf("user:%s\n",url_result_t.user);
printf("pass:%s\n",url_result_t.pass);
printf("port:%d\n",url_result_t.port);
printf("domain:%s\n",url_result_t.domain);
printf("svr_dir:%s\n",url_result_t.svr_dir);
printf("svr_ip:%s\n",url_result_t.svr_ip);
printf("-------------end---------------\n");
}
执行结果

第七:代码获取
完整代码可以进入我的仓库获取
https://gitee.com/yikoulinux/url边栏推荐
- List map basic notes
- JS module, closure application
- Matlab digital image processing experiment 2: single pixel spatial image enhancement
- Wechat campus laundry applet graduation design finished product (6) opening defense ppt
- 浏览器内核模块组成
- NoSQL -- three theoretical cornerstones of NoSQL -- cap -- Base -- final consistency
- 小程序毕设作品之微信校园洗衣小程序毕业设计成品(6)开题答辩PPT
- Common types of electric slip rings
- idea Gradle7.0+ :Could not find method compile()
- 软考 系统架构设计师 简明教程 | 系统设计
猜你喜欢

Zoom, translation and rotation of OpenCV image

小程序毕设作品之微信校园洗衣小程序毕业设计成品(2)小程序功能

小程序毕设作品之微信校园洗衣小程序毕业设计成品(4)开题报告

SQL tutorial: introduction to SQL aggregate functions

【实习经验】Date工具类中添加自己实现的方法

Matlab digital image processing experiment 2: single pixel spatial image enhancement
![[C Advanced] pointer array vs array pointer](/img/1e/33f9cc9446dcad8cdb78babbb5a22c.jpg)
[C Advanced] pointer array vs array pointer

期货公司开户后续会有哪些服务?

MFC FTP creates multi-level folders and uploads files to the specified directory of FTP

Figure 8 shows you how to configure SNMP
随机推荐
Browser kernel module composition
Deep confidence network (DBN) [the classical DBN network structure is a deep neural network composed of several layers of RBM (restricted Boltzmann machine) and one layer of BP]
16 VMware horizon 2203 virtual desktop-win10 automatic desktop pool full clone dedicated (XVI)
MFC FTP creates multi-level folders and uploads files to the specified directory of FTP
MySQL high availability practical solution MHA
Keras深度学习实战——推荐系统数据编码
List map basic notes
基于C语言实现线性表的建立、插入、删除、查找等基本操作
Verilog's system tasks - $fopen, $fclose and $fddisplay, $fwrite, $fstrobe, $fmonitor
js将数组根据指定属性值分组成二维数组
小程序毕设作品之微信校园洗衣小程序毕业设计成品(1)开发概要
将目标检测大尺寸图片裁剪成固定尺寸图片
软考 系统架构设计师 简明教程 | 软件系统建模
小程序毕设作品之微信校园洗衣小程序毕业设计成品(6)开题答辩PPT
Database kernel developer, worth a mug!!!
小程序毕设作品之微信校园洗衣小程序毕业设计成品(4)开题报告
13、用户web层服务(一)
Unapp prevents continuous click errors
Differences between shell environment variables and set, env, export
SQL教程之 SQL 聚合函数入门教程