1. 程式人生 > 其它 >C語言實現url解析小例項

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:[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

或者公眾號後臺回覆關鍵字:url