Linux下服務器IP地址、端口、域名解析

前言

就喜歡使用linux系統的用戶來說,命令行終端對於我們來說再熟知不過了,用戶通過使用命令和系統進行交互,Linux命令的格式一般是命令 + 選項 + 參數,當輸入命令的時候,shell通過解析參數而讓內核執行不同的功能。這篇文章記錄一下我學習命令行參數解析的內容,並編寫一個服務器ip地址解析的小程序,爲後期做項目做好準備。😀

GNU C提供的參數解析函數

getopt和getopt_long頭文件都是include <getopt.h>。

getopt

int getopt(int argc, char * const argv[],const char *optstring);

參數解析:
argc:命令行參數的個數
argv:保存命令參數的字符串數組。其類型不是很清楚,所以學習一下:

  • char * const ptr:可以將其看成 char *(const ptr),所以ptr是一個常量指針,不可以修改指針的值,但是可以修改指針所指向的內容。
  • char const *ptr 和 const char *ptr :指向字符常量的指針,可以對指針修改,但是不可以改變指針所指的內容。
  • 另外,argv還是一個二級指針。

optstring:命令行選項聲明,比如終端下"cp -r file/ file1/","-r"就是段選項,在函數參數用a:b::cd:表示命令是否帶參數:

  • a:後面根一個冒號,意思是選項a後面帶有參數。
  • b::後面跟兩個冒號,意思是選項b後面可以帶參數也可以不帶參數。如果要帶參數,參數和冒號之間不能有空格,比如:-b123456
  • c後面沒有冒號,意思是c選項不帶參數。
  • 全局變量chat *optarg:指向當前選項後面的參數。比如:-b123456,*optarg = 123456。所以在編寫參數解析功能模塊時,不需要定義就可以直接使用。

返回值:所有參數解析完畢,返回-1。

getopt_long

Linux下不僅有短選項,如gcc -v,還有長選項如gcc --version,getopt只能處理短選項,getopt_long彌補了它的缺陷,可以處理長選項,比getopt多了兩個參數。

int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);

參數解析:
argc:命令行參數的個數
argv:保存命令參數的字符串數組。
optstring:命令行短選項聲明。
longopts:結構體數組,用於描述長選項的解析方式。

struct option
{
    const char *name;
    int has_arg;
    int *flag;
    int val;
};
const char *name:選項的名稱譬如“help”。

int has_arg:描述了選項是否有選項參數。
0 no_argument 選項沒有參數
1 required_argument 選項需要參數 
2 optional_argument 選項參數可選

int *flag 和 int val 這兩個參數有關聯,如果這個指針爲NULL,那麼getopt_long()返回該結構val字
段中的數值。如果該指針不爲NULLgetopt_long()會使得它所指向的變量中填入val字段中的數值,並
getopt_long()返回0。如果flag不是NULL,但未發現長選項,那麼它所指向的變量的數值不變。

longindex:結構體數組的下標,我們一般對其不關心,直接填NULL。

參考學習:https://www.cnblogs.com/NickQ/p/11368656.html
https://blog.csdn.net/techhome803/article/details/8507839

域名解析函數

struct hostent* gethostbyname(const char *name);

參數解析:

  • name:服務器域名地址

返回:解析完成返回一個hostent結構體。

struct hostent
{
    char *h_name;//主機規範名
    char ** h_aliases;//別名
    short h_addrtype;//主機IP地址的類型ipv4/ipv6
    short h_length;//主機ip地址的長度
    char ** h_addr_list;//表示的是主機的ip地址,
    //這個是以網絡字節序存儲的。
    //需要調用inet_ntop();
};

一個簡單的例子

功能實現說明:通過對命令行參數解析,實現解析百度域名。

  • 如果用私有ip地址訪問服務器,必須指定ip和端口,也就是執行程序時要帶上選項-i + IP地址 -p + 端口號。
  • 如果用域名訪問則只需帶選項-d + 域名。
  • 如果帶選項-h,打印幫助信息。
  • 帶其他選項,或者不帶選項,程序打印幫助信息
#include<stdio.h>
#include<getopt.h>
#include<stdlib.h>

#deine ALL_IP 0
//函數聲明
static void print_usage(char *order);
char* DNS(char *domain);
int argument_parse(int argc,char **argv,char **serv_IP,int *serv_port);


int main(int argc,char **argv)
{
    char                *serv_IP = NULL;//服務器IP
    int                 serv_port = 0;//服務器端口
    int                 rv = -1;//函數返回值

    rv = argument_parse(argc,argv,&serv_IP,&serv_port);//參數解析
    if(0 == rv)
    {
        printf("解析出服務器serv_IP爲:%s\n",serv_IP);
        printf("服務器端口爲:%d\n",serv_port);
    }

    return 0;
}

/*功能:打印幫助信息
 * 參數:order:執行的程序名
 * 返回值:無*/
static void print_usage(char *order)
{   
    printf("%s usages:\n",order);
    printf("-I(IP):server IP\n");
    printf("-p(port):server port\n");
    printf("-d(domain):domain name prase\n");
    printf("-h(help):help information\n");

}

/*功能:域名解析
 *參數:domain:傳入域名
 *返回:返回一個點分十進制IP*/
char* DNS(char *domain)  
{                        
    struct hostent *host = (struct hostent *)malloc(sizeof(struct hostent));//保存解析之後的ip地址信息
                         
    if(!domain)          
    {
        return NULL;
    }

    host = gethostbyname(domain);//域名解析函數
    if(!host)
    {
        return NULL;
    }

//因爲有的域名地址關聯着很多ip地址,所以可以通過修改宏ALL_IP用for循環依次打印
#if ALL_IP
    for(int i = 0; host->h_addr_list[i]; i++)
    {
        printf("%d ip:%s\n",i,inet_ntoa(*(struct in_addr*)host->h_addr[i]));

    }
#endif                                                
                                                      
    return inet_ntoa(*(struct in_addr*)host->h_addr);//返回一個點分十進制的IP指針
}

/* 功能:參數解析
 * 參數:argc:參數個數
 *       argv:保存參數的字符串指針
 *       serv_IP:服務器ip(output)
 *       serv_port:服務器端口(output)
 * 返回值:成功返回0,錯誤返回-1*/
int argument_parse(int argc,char **argv,char **serv_IP,int *serv_port)
{
    int                 optopt;//getopt返回值
    int                 domain_mark = 0;//域名解析標誌

    //定義選項處理方案
    struct option       long_options[]=
    {
        {"IP",1,NULL,'i'},
        {"port",1,NULL,'p'},
        {"help",0,NULL,'h'},
        {0,0,0,0}

    };

    while((optopt=getopt_long(argc,argv,"i:p:d:h",long_options,NULL)) > 0)
    {

        switch(optopt)
        {


            case 'i':
                *serv_IP = optarg;
                   break;
            case 'p':
                *serv_port = atoi(optarg);
                break;
            case 'd':
                *serv_IP = DNS(optarg);//域名解析
                domain_mark = 1;//表示進行了域名解析
                printf("serv_ip=%s\n",*serv_IP);
                break;
            case 'h':
                print_usage(argv[0]);
                break;
            default:
                break;

        }

    }

    if(!(*serv_IP)||(!serv_port && !domain_mark))
    {
        print_usage(argv[0]);
        return -1;
    }

    return 0;
}

編譯測試結果:
在這裏插入圖片描述
用這個ip地址訪問百度:
在這裏插入圖片描述
可以成功訪問。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章