• ftp server来源分析20140602


    ftp  server学习位和源代码分析片
    记录自己的第一个开源的分析过程:
    从源代码:野狐灯(我接下来的几篇文章是从源头:野狐灯,每个以下哪项不是他们设置。)


    20140602


    Ftp的源码目录例如以下
    dxyh.h     dxyh_lib.c            包裹函数(经常使用的) 
    dxyh_thread.h  dxyh_thread_lib.c   线程包裹函数
    Ftpd.h   ftpd.c                  主代码 
    ftpd_main.c                      程序入口
    error.h   error.c                  错误处理的函数
    record.h      record.c            生成相关的记录
    Makefile                        makefile文件
    readme   自己加入的改动的记录
    首先是把每一个文件大致浏览了一下知道大概的过程
    从ftpd_main.c開始分析之旅
    //ftpd_main.c
      2 #include <stdio.h>
      3 #include "ftpd.h"
      4 #include "record.h"
      5 #include "error.h"
      6 #include "dxyh.h"
      7 
      8 int main(int argc, char **argv)
      9 {
     10         int listenfd;
     11 
     12         ftpd_init();
     13         ftpd_parse_args(argc, argv);
     14         listenfd = ftpd_create_serv();
     15         ftpd_do_loop(listenfd);
     16         return 0;
     17 }
     18 
    在ftpd.c 中大概看了一下 ftpd_init();感觉没什么
    再看ftpd_parse_args(argc,argv)
    感觉内容挺多的,
    先看了一下以下这个函数
    getopt_long()


    #include <getopt.h>
    2函数原型
    编辑


    int getopt_long(int argc, char * const argv[],
    const char *optstring,
    const struct option *longopts, int *longindex);
    3函数说明
    编辑


    getopt被用来解析命令行选项參数。
    getopt_long支持长选项的命令行解析,使用man getopt_long,得到其声明例如以下:
    int getopt_long(int argc, char * const argv[],const char *optstring, const struct option *longopts,int *longindex);
    函数中的argc和argv通常直接从main()的两个參数传递而来。

    optsting是选项參数组成的字符串:
    字符串optstring能够下列元素:
    1.单个字符,表示选项,
    2.单个字符后接一个冒号:表示该选项后必须跟一个參数。參数紧跟在选项后或者以空格隔开。

    该參数的指针赋给optarg。


    3 单个字符后跟两个冒号,表示该选项后能够有參数也能够没有參数。

    假设有參数。參数必须紧跟在选项后不能以空格隔开。该參数的指针赋给optarg。

    (这个特性是GNU的扩张)。
    optstring是一个字符串,表示能够接受的參数。比如,"a:b:cd"。表示能够接受的參数是a,b,c,d,当中,a和b參数后面跟有很多其它的參数值。(比如:-a host -b name)
    參数longopts,事实上是一个结构的实例:
    struct option {
    const char *name; //name表示的是长參数名
    int has_arg; //has_arg有3个值,no_argument(或者是0),表示该參数后面不跟參数值
    // required_argument(或者是1),表示该參数后面一定要跟个參数值
    // optional_argument(或者是2),表示该參数后面能够跟。也能够不跟參数值
    int *flag;
    //用来决定。getopt_long()的返回值究竟是什么。

    假设flag是null(通常情况),则函数会返回与该项option匹配的val值;假设flag不是NULL。则将val值赋予flag所指向的内存。而且返回值设置为0。
    int val; //和flag联合决定返回值
    }
    參数longindex,表示当前长參数在longopts中的索引值。[1]
    给个样例:
    struct option long_options[] = {
    {"a123", required_argument, 0, 'a'},
    {"c123", no_argument, 0, 'c'},
    }
    如今,假设命令行的參数是-a 123,那么调用getopt_long()将返回字符'a',而且将字符串123由optarg返回(注意注意!字符串123由optarg带回!

    optarg不须要定义,在getopt.h中已经有定义),那么。假设命令行參数是-c。那么调用getopt_long()将返回字符'c',而此时,optarg是null。

    最后。当getopt_long()将命令行所有參数所有解析完毕后。返回-1。


    4注意
    编辑


    required_argument(或者是1)时。參数输入格式为:--參数 值 或者 --參数=值。
    optional_argument(或者是2)时,參数输入格式仅仅能为:--參数=值。
    5范例
    编辑


    #include <stdio.h>
    #include <getopt.h>
    char *l_opt_arg;
    char* const short_options = "nbl:";
    struct option long_options[] = {
    { "name", 0, NULL, 'n' },
    { "bf_name", 0, NULL, 'b' },
    { "love", 1, NULL, 'l' },
    { 0, 0, 0, 0},
    };
    int main(int argc, char *argv[])
    {
    int c;
    while((c = getopt_long (argc, argv, short_options, long_options, NULL)) != -1)
    {
    switch (c)
    {
    case 'n':
    printf("My name is XL. ");
    break;
    case 'b':
    printf("His name is ST. ");
    break;
    case 'l':
    l_opt_arg = optarg;
    printf("Our love is %s! ", l_opt_arg);
    break;
    }
    }
    return 0;
    }
    [root@localhost wyp]# gcc -o getopt getopt.c
    [root@localhost wyp]# ./getopt -n -b -l forever
    My name is XL.
    His name is ST.
    Our love is forever!
    [root@localhost liuxltest]#
    [root@localhost liuxltest]# ./getopt -nb -l forever
    My name is XL.
    His name is ST.
    Our love is forever!
    [root@localhost liuxltest]# ./getopt -nbl forever
    My name is XL.
    His name is ST.
    Our love is forever!


    看到有err_msg()这个函数
    在error.c 中找到这个函数
    又查找va_list 的使用方法


    va_list


    VA_LIST 是在C语言中解决变參问题的一组宏,所在头文件:#include <stdarg.h>
    #ifdef _M_ALPHA
    typedef struct {
    char *a0; /* pointer to first homed integer argument */
    int offset; /* byte offset of next parameter */
    } va_list;
    #else
    typedef char * va_list;
    #endif
    _M_ALPHA是指DEC ALPHA(Alpha AXP)架构。

    所以普通情况下va_list所定义变量为字符[1]指针。





    INTSIZEOF 宏,获取类型占用的空间长度,最小占用长度为int的整数倍:
    #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )


    ~是位取反的意思。
    _INTSIZEOF(n)整个做的事情就是将n的长度化为int长度的整数倍。
    比方n为5。二进制就是101b,int长度为4,二进制为100b,那么n化为int长度的整数倍就应该为8。
    ~(sizeof(int) - 1) )就应该为~(4-1)=~(00000011b)=11111100b。这样不论什么数& ~(sizeof(int) - 1) )后最后两位肯定为0,就肯定是4的整数倍了。
    (sizeof(n) + sizeof(int) - 1)就是将大于4m但小于等于4(m+1)的数提高到大于等于4(m+1)但小于4(m+2)。这样再& ~(sizeof(int) - 1) )后就正好将原长度补齐到4的倍数了。




    VA_START宏。获取可变參数列表的第一个參数的地址(ap是类型为va_list的指针,v是可变參数最右边的參数):
    #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
    VA_ARG宏,获取可变參数的当前參数,返回指定类型并将指针指向下一參数(t參数描写叙述了当前參数的类型):
    #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
    VA_END宏。清空va_list可变參数列表:
    #define va_end(ap) ( ap = (va_list)0 )
    3使用方法
    编辑


    (1)首先在函数里定义一具VA_LIST型的变量。这个变量是指向參数的指针。
    (2)然后用VA_START宏初始化刚定义的VA_LIST变量;
    (3)然后用VA_ARG返回可变的參数,VA_ARG的第二个參数是你要返回的參数的类型(假设函数有多个可变參数的。依次调用VA_ARG获取各个參数);
    (4)最后用VA_END宏结束可变參数的获取。
    4注意问题
    编辑


    (1)可变參数的类型和个数全然由程订购代码控制,它不智能识别不同参数的数量和类型;
    (2)假设我们并不需要每个参数一一详细解释。仅需要被复制到缓冲器变量列表,可用的vsprintf功能;
    (3)由于编译器检查的函数原型可变参数不够严谨格,故障排除不利的编程.它并不能帮助我们写出高质量的代码;


    感觉很多东西,快来硬着头皮继续往下看!

  • 相关阅读:
    Selenium协议
    seleniumxpath定位方法详解
    selenium 数据驱动测试 ddt
    为什么要使用Gard代替if判断
    TCP的爱情故事
    C#面试之 值类型和引用类型区别
    Qt QFileSystemModel 的使用
    QStringListModel的使用
    工作问题记录:elementUI 中表单校验问题
    c++读书笔记
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4602145.html
Copyright © 2020-2023  润新知