C語言實現url解析小例項
阿新 • • 發佈:2022-03-15
一、前言
前面一口君寫了一篇關於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