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

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

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

编译运行:

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

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

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 ;
} void str_upper(char *str)
{
} long long str_to_longlong(const char *str)
{
return ;
} unsigned int str_octal_to_uint(const char *str)
{
unsigned int result = ;
return ;
}

接下来一个个函数实现:

①:去除字符串\r\n:rhstr_trim_crlf()

实现思路:

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

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

这时得在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+);
}
}

【说明】:上面用到了几个跟字符串相关的处理函数,需要熟悉一下: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 = ;
long long mult = ;//这个表示乘法系数
unsigned int len = strlen(str);
unsigned int i; if (len > )//对长度进限制,因为long long也是有大小限制的
return ; for (i=; i<len; i++)
{
char ch = str[len-(i+)];
long long val;
if (ch < '' || ch > '')//如果里面是非数字字符,则直接返回0
return ; val = ch - '';
val *= mult;
result += val;
mult *= ;//系数乘以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*+1=1

1*+2=12

12*+3=123

123*+4=1234

....

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

0*+1=1

1*+2=12

12*+3=123

123*+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网络编程综合运用之MiniFtp实现(五)的更多相关文章

  1. Linux网络编程综合运用之MiniFtp实现(一)

    春节过后,万物复苏,在这元宵佳节的前一天,决定继续开启新年的学习计划,生命在于运动,提高源于学习,在经过漫长的Linux网络编程学习后,接下来会以一个综合的小项目来将所学的知识点综合运用,首先是对项目 ...

  2. Linux网络编程综合运用之MiniFtp实现(四)

    从今天开始,正式进入MiniFtp的代码编写阶段了,好兴奋,接下来很长一段时间会将整个实现过程从无到有一点点实现出来,达到综合应用的效果,话不多说正入正题: 这节主要是将基础代码框架搭建好,基于上节介 ...

  3. Linux网络编程综合运用之MiniFtp实现(九)

    上次中实现了FTP命令的映射来避免很多if....else的判断,这次主要是开始实现目录列表的传输,先看一下目前实现的: 数据连接创建好之后则开始进行目录列表的传输了,而要传输目录列表,首先要将目录列 ...

  4. Linux网络编程综合运用之MiniFtp实现(八)

    上节中实现了"USER"和"PASS"命令,如下: 事实上FTP是有很多命令组成的,如果就采用上面的这种方法来实现的话,就会有很多if...else if语句, ...

  5. Linux网络编程综合运用之MiniFtp实现(七)

    上节中实现了配置文件的解析,这节来实现用户登录的验证,首先用客户端来登录vsftpd来演示登录的过程: 接着再连接miniftpd,来看下目前的效果: 接下来实现它,与协议相关的模块都是在ftppro ...

  6. Linux网络编程综合运用之MiniFtp实现(六)

    间隔了一周时间没写了,由于今年的股势行情貌似不错的样子,对于对股市完全不懂的我也在蠢蠢欲动,所以最近一周业余时间在“不务正业”-----学习炒股.发现学习它其实挺费神的,满脑子都是走势图,而且是神经有 ...

  7. Linux网络编程综合运用之MiniFtp实现(三)

    前面已经对FTP相关的一些概念有了基本的认识,接下来就要进入代码编写阶段了,也是非常兴奋的阶段,在开启这个它之前先对项目需求进行一个梳理,对其我们要实现的FTP服务器是一个什么样子. ftp命令列表 ...

  8. 【深入浅出Linux网络编程】 "开篇 -- 知其然,知其所以然"

    [深入浅出Linux网络编程]是一个连载博客,内容源于本人的工作经验,旨在给读者提供靠谱高效的学习途径,不必在零散的互联网资源中浪费精力,快速的掌握Linux网络编程. 连载包含4篇,会陆续编写发出, ...

  9. 【linux草鞋应用编程系列】_5_ Linux网络编程

    一.网络通信简介   第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章.   二.linux网络通信     在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...

随机推荐

  1. 11点睛Spring4.1-Property Editor

    11.1 Propert Editor property editor是JavaBeans API的一项特性,用来字符和属性值之间的互相转换(如2014-03-02和Date类型的互相转换) spri ...

  2. LeetCode:打印零与奇偶数【1116】

    LeetCode:打印零与奇偶数[1116] 题目描述 假设有这么一个类: class ZeroEvenOdd { public ZeroEvenOdd(int n) { ... } // 构造函数 ...

  3. 【译】Vue源码学习(一):Vue对象构造函数

    本系列文章详细深入Vue.js的源代码,以此来说明JavaScript的基本概念,尝试将这些概念分解到JavaScript初学者可以理解的水平.有关本系列的一些后续的计划和轨迹的更多信息,请参阅此文章 ...

  4. js 验证手机号

    <script> var reg = /^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\d{8}$/; function ver ...

  5. 莫比乌斯反演求LCM的另一种做法

    一个经典问题 求 \[ \sum_{k=1}^n\mathbb{lcm}(k,n) \] 一般的做法是使用\(\varphi(n)\)函数. 不经典的做法 \[ \begin{align*} \sum ...

  6. JDBC(连接数据库的四个主要步骤)

    JDBC连接数据库 ?创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.l ...

  7. e.g. i.e. etc. et al. w.r.t. i.i.d.英文论文中的缩写语

    e.g. i.e. etc. et al. w.r.t. i.i.d. 用法:, e.g., || , i.e., || , etc. || et al., || w.r.t. || i.i.d. e ...

  8. linux定时任务每隔5分钟向文本追加一行

    编写shell脚本 test.sh内容如下,上传到linux的root目录 更改文件权限 chmod  777   test.sh 编辑定时任务 crontab  -e */5    *  *  *  ...

  9. 微信自研生产级paxos类库PhxPaxos实现原理介绍

    转载自:   http://mp.weixin.qq.com/s?__biz=MzI4NDMyNTU2Mw==&mid=2247483695&idx=1&sn=91ea4229 ...

  10. golang之方法

    golang中的方法是作用在指定的数据类型上的(即:和指定 数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是在struct. 方法的使用: type Person struct { Num i ...