• Linux网络编程综合运用之MiniFtp实现(五)


    转眼兴奋的五一小长假就要到来了,在放假前夕还是需要保持一颗淡定的心,上次中已经对miniFTP有基础框架进行了搭建,这次继续进行往上加代码,这次主要还是将经历投射到handle_child()服务进程上来,其它的先不用关心:

    而它主要是完成FTP协议相关的功能,所以它的实现放在了ftpproto.c,目前连接成功之后效果是:

    其中"USER webor2006"后面是包含" "的,FTP的协议规定每条指令后面都要包含它,这时handle_child()函数就会收到这个命令并处理,再进行客户端的一些应答,客户端才能够进行下一步的动作,由于目前还没有处理该命令,所以客户端阻塞了,接下来读取该指令来打印一下:

    编译运行:

    接下来命令中的 ,接下来的操作会涉及到一些字符串的处理,所以先来对其进行封装一下,具体字符串的处理函数如下:

    这里创建一个新的字符串模块,来将上面相关的函数都放一起:

    str.h:

    #ifndef _STR_H_
    #define _STR_H_
    
    void str_trim_crlf(char *str);
    void str_split(const char *str , char *left, char *right, char c);
    int str_all_space(const char *str);
    void str_upper(char *str);
    long long str_to_longlong(const char *str);
    unsigned int str_octal_to_uint(const char *str);
    
    
    #endif /* _STR_H_ */

    str.c:

    #include "str.h"
    #include "common.h"
    
    void str_trim_crlf(char *str)
    {
    
    }
    
    void str_split(const char *str , char *left, char *right, char c)
    {
    
    }
    
    int str_all_space(const char *str)
    {
        return 1;
    }
    
    void str_upper(char *str)
    {
    }
    
    long long str_to_longlong(const char *str)
    {
        return 0;
    }
    
    unsigned int str_octal_to_uint(const char *str)
    {
        unsigned int result = 0;
        return 0;
    }

    接下来一个个函数实现:

    ①:去除字符串 :rhstr_trim_crlf()

    实现思路:

    void str_trim_crlf(char *str)
    {
        char *p = &str[strlen(str)-1];
        while (*p == '
    ' || *p == '
    ')
            *p-- = '';
    }

    接下来来测试一下该函数是否管用:

    这时得在Makefile中增加字符串模块了:

    编译运行:

    ②:解析FTP命令与参数:str_split()

    接下来将命令进行分割:

    下面则实现该函数:

    void str_split(const char *str , char *left, char *right, char c)
    {
        //首先查找要分割字符串中首次出现字符的位置
        char *p = strchr(str, c);
        if (p == NULL)
            strcpy(left, str);//表示没有找到,该命令没有参数,则将一整串拷贝到left中
        else
        {//表示找到了,该命令有参数
            strncpy(left, str, p-str);
            strcpy(right, p+1);
        }
    }

    【说明】:上面用到了几个跟字符串相关的处理函数,需要熟悉一下:strchr、strncpy、strcpy。

    下面编译运行一下:

    包含头文件:

    再次编译运行:

    ③:判断所有的字符是否为空白字符:str_all_space()

    编写一下测试代码:

    编译运行:

    查看man帮助将其加上:

    再次编译运行:

    ④:将字符串转换成大写:str_upper()

    编写测试函数:

    编译运行:

    加入头文件:

    再次编译运行:

    发生这种错误不用怕, 交给gdb:

    其实这个错误是一个很好检验C语言基本功的,修改程序如下:

    再次编译运行:

    ⑤:将字符串转换为长长整型:str_to_longlong()

     可能会想到atoi系统函数可以实现,但是它返回的是一个整型:

    但是也有一个现成的函数可以做到:atoll:

    所以可以先用它来实现:

    long long str_to_longlong(const char *str)
    {
        return atoll(str);
    }

    编写测试代码并运行:

    但是不是所有的系统都支持它,因此这里我们自己来实现,其实现思路也比较简单,规则如下:

    12345678=8*(10^0) + 7*(10^1) + 6*(10^2) + ..... + 1*(10^7)

    所以实现如下:

    long long str_to_longlong(const char *str)
    {
        long long result = 0;
        long long mult = 1;//这个表示乘法系数
        unsigned int len = strlen(str);
        unsigned int i;
    
        if (len > 15)//对长度进限制,因为long long也是有大小限制的
            return 0;
    
    
        for (i=0; i<len; i++)
        {
            char ch = str[len-(i+1)];
            long long val;
            if (ch < '0' || ch > '9')//如果里面是非数字字符,则直接返回0
                return 0;
    
            val = ch - '0';
            val *= mult;
            result += val;
            mult *= 10;//系数乘以10
        }
        return result;
        //return atoll(str);
    }

    下面编译运行:

    其中计算方式是从后往前的,所以可以将for循环进行修改一下变得更加简单一些:

     再次编译运行:

    这里面是个坑,跟无符号整形有关,也就是这句话:

    这里来打印一下i的变化就明白了:

    输出如下:

    其原因是:

    所以要解决此问题,很简单,直接将无符号给去掉既可:

    再编译运行:

    ⑥:将八进制的整形字符串转换成无符号整型str_octal_to_uint()

    其实现原理跟上面的差不多:

    123456745=5*(8^0) + 4*(8^1) + 7*(8^2) + .... + 1*(8^8)

    代码编写也跟上面函数一样,这里采用另外一种方式来实现,从高位算起:

    先拿10进制来进行说明,好理解:

    123456745可以经过下面这个换算得到:

    0*10+1=1

    1*10+2=12

    12*10+3=123

    123*10+4=1234

    ....

    所以换算成八进制,其原理就是这样:

    0*8+1=1

    1*8+2=12

    12*8+3=123

    123*8+4=1234

    ....

    所以依照这个原理就可以进行实现了,由于八进制可能前面为0,如:0123450,所以需要把第一位0给过滤掉,如下:

    而公式里面应该是result*8+digit来进行计算,这里用位操作来改写,也就是result*8=result <<= 3,移位操作效率更加高效,所以最终代码如下:

    下面则编写测试代码,来看下是否有效:

    编译运行:

    下面我们手动来验证下结果是否等于457:

    711计算如下:

    ①、7*8+1=57

    ②、57*8+1=456+1=457

    所以结果是正常的。

    以上就是关于字符串需要用到的工具模块,最后回到主程序来:

    好了,下节继续完善~~

  • 相关阅读:
    【Linux】VMware及VirtualBox网络配置
    【Linux】VirtualBox安装ubuntu排错LowGraphic
    【Hadoop】Win7上搭建Hadoop开发环境,方法一
    【JAVA】配置JAVA环境变量,安装Eclipse
    Eureka自我保护机制
    zookeeper代替eureka作为SpringCloud的服务注册中心
    mybatisplus代码生成器
    条件构造器 EntityWrapper (重要)
    idea 常用快捷键
    MybatisPlus的通用 CRUD
  • 原文地址:https://www.cnblogs.com/webor2006/p/4458899.html
Copyright © 2020-2023  润新知