C语言实现url解析小实例
一、前言
前面一口君写了一篇关于url的文章:
《一文带你理解URI 和 URL 有什么区别?》
本篇在此基础上,编写一个简单的用于解析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:pass@baidu.com/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:pass@baidu.com/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:pass@baidu.com/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
或者公众号后台回复关键字:url
C语言实现url解析小实例的更多相关文章
- (转)使用 CJSON 在C语言中进行 JSON 的创建和解析的实例讲解
		
使用 CJSON 在C语言中进行 JSON 的创建和解析的实例讲解 本文用代码简单介绍cjson的使用方法,1)创建json,从json中获取数据.2)创建json数组和解析json数组 1. 创 ...
 - Objective-C之@类别小实例
		
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
 - Python(五)编程小实例
		
Python(五)编程小实例 抓取网页信息,并生成txt文件内容! Python抓取网页技能--Python抓取网页就是我们常看见的网络爬虫,我们今天所要用到的就是我们Python中自带的模块,用这些 ...
 - python+pcap+dpkt 抓包小实例
		
#!/usr/bin/env python # -*- coding: utf-8 -*- """ 网络数据包捕获与分析程序 """ imp ...
 - Python_爬虫小实例
		
爬虫小实例 一.问题描述与分析 Q:查询某一只股票,在百度搜索页面的结果的个数以及搜索结果的变化. 分析: 搜索结果个数如下图: 搜索结果的变化:通过观察可以看到,每个一段时间搜索结果的个数是有所变化 ...
 - Django 小实例S1 简易学生选课管理系统 4 实现登录页面
		
Django 小实例S1 简易学生选课管理系统 第4节--实现登录页面 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 本文涉及到的新的额外知识点: ...
 - Objective-C之代理设计模式小实例
		
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
 - OC小实例关于init方法不小心的错误
		
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
 - C语言文件操作解析(五)之EOF解析(转载)
		
C语言文件操作解析(五)之EOF解析 在C语言中,有个符号大家都应该很熟悉,那就是EOF(End of File),即文件结束符.但是很多时候对这个理解并不是很清楚,导致在写代码的时候经常出错,特 ...
 - ssh框架的小实例(用户登录)
		
刚学SSH框架写一个小实例,以便以后查看: 本案例简单的实现一个用户登录: 数据库方面就不写了,自己领悟吧!哈哈(根据user.hbm.xml文件就知道了) 我们一般可以创建下面几个包,什么意思呢,自 ...
 
随机推荐
- 【仿真】Carla简易安装 Window Ubuntu均适用 附ROS的简单连接 [0]
			
参考与前言 CARLA Documentation 官方文档 后续链接:[仿真]Carla介绍与使用 [1] 本篇创建于 2020/12/18,安装方式为压缩包安装,无需UE4等软件,但是前提是需要一 ...
 - 3.8折年终钜惠,RK3568J国产工业评估板
			
3.8折年终钜惠,RK3568J国产工业评估板活动火热进行中,错过等一年! -核心板国产化率100%,提供报告-瑞芯微四核ARM Cortex-A55@1.8GHz-4K视频解码.1080P视频编码. ...
 - 【ClickHouse】1:clickhouse安装 (CentOS7)
			
一:安装clickhouse 官网地址:https://clickhouse.tech/#quick-start 按照官网提供的方法快速安装:(依次执行) sudo yum install yum-u ...
 - Vue2 整理(一):基础篇
			
前言 首先说明:要直接上手简单得很,看官网熟悉大概有哪些东西.怎么用的,然后简单练一下就可以做出程序来了,最多两天,无论Vue2还是Vue3,就都完全可以了,Vue3就是比Vue2多了一些东西而已,所 ...
 - 面试官:Dubbo一次RPC调用会经过哪些环节?
			
大家好,我是三友~~ 今天继续探秘系列,扒一扒一次RPC请求在Dubbo中经历的核心流程. 本文是基于Dubbo3.x版本进行讲解 一个简单的Demo 这里还是老样子,为了保证文章的完整性和连贯性,方 ...
 - C#-WPF初学
			
1.新建一个WPF的应用: 2.拖拽控件并布局好: [小技巧]选中控件,点击"回形针"即可让该控件跟随窗口自动调整大小: 3.编写代码: 主程序代码如下: namespace Wp ...
 - RS232转PN协议网关模块连接PLC和霍尼韦尔条码扫描器通信
			
为了更快地输入信息,许多设备都配备了条码扫描器,但条码扫描器不能直接与CPU通信.最直接和方便的方法是加RS232转PN协议网关模块(BT-PNR20).本文将深入研究如何利用巴图自动化的RS232转 ...
 - [oeasy]python0116_文字的起源_苏美尔文明_楔形文字_两河流域
			
文字起源 回忆上次内容 上次回顾了西里尔字符的编码过程 KOI-7 KOI-8 ISO-8859 系列进行总结 字符扩展 ascii 共 16 种 由iso组织制定 从 iso-8859-1 到 ...
 - Masked Popcount 题解
			
背景 罚了一发,太菜了.为什么我终于有时间的时候她要考试? 题意 给你 \(n,m\),问 \(\sum_{i=0}^{n}popcount(i \&m)\). 其中 \(\&\) 代 ...
 - iOS开发基础142-广告归因
			
IDFA IDFA是苹果为iOS设备提供的一个唯一标识符,专门用于广告跟踪和相关的营销用途.与之对应的,在Android平台的是谷歌广告ID(Google Advertising ID). IDFA的 ...