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地址访问百度:
在这里插入图片描述
可以成功访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值