天天看點

Linux網絡程式設計綜合運用之MiniFtp實作(五)

轉眼興奮的五一小長假就要到來了,在放假前夕還是需要保持一顆淡定的心,上次中已經對miniFTP有基礎架構進行了搭建,這次繼續進行往上加代碼,這次主要還是将經曆投射到handle_child()服務程序上來,其它的先不用關心:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

而它主要是完成FTP協定相關的功能,是以它的實作放在了ftpproto.c,目前連接配接成功之後效果是:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

其中"USER webor2006"後面是包含"\r\n"的,FTP的協定規定每條指令後面都要包含它,這時handle_child()函數就會收到這個指令并處理,再進行用戶端的一些應答,用戶端才能夠進行下一步的動作,由于目前還沒有處理該指令,是以用戶端阻塞了,接下來讀取該指令來列印一下:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

接下來指令中的\r\n,接下來的操作會涉及到一些字元串的處理,是以先來對其進行封裝一下,具體字元串的處理函數如下:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

這裡建立一個新的字元串子產品,來将上面相關的函數都放一起:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

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;
}      

接下來一個個函數實作:

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

實作思路:

Linux網絡程式設計綜合運用之MiniFtp實作(五)
void str_trim_crlf(char *str)
{
    char *p = &str[strlen(str)-1];
    while (*p == '\r' || *p == '\n')
        *p-- = '\0';
}      

接下來來測試一下該函數是否管用:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

這時得在Makefile中增加字元串子產品了:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

②:解析FTP指令與參數:str_split()

接下來将指令進行分割:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

下面則實作該函數:

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。

下面編譯運作一下:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

包含頭檔案:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

再次編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

③:判斷所有的字元是否為空白字元:str_all_space()

Linux網絡程式設計綜合運用之MiniFtp實作(五)

編寫一下測試代碼:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

檢視man幫助将其加上:

Linux網絡程式設計綜合運用之MiniFtp實作(五)
Linux網絡程式設計綜合運用之MiniFtp實作(五)

再次編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

④:将字元串轉換成大寫:str_upper()

Linux網絡程式設計綜合運用之MiniFtp實作(五)
Linux網絡程式設計綜合運用之MiniFtp實作(五)

編寫測試函數:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

加入頭檔案:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

再次編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

發生這種錯誤不用怕, 交給gdb:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

其實這個錯誤是一個很好檢驗C語言基本功的,修改程式如下:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

再次編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

⑤:将字元串轉換為長長整型:str_to_longlong()

 可能會想到atoi系統函數可以實作,但是它傳回的是一個整型:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

但是也有一個現成的函數可以做到:atoll:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

是以可以先用它來實作:

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

編寫測試代碼并運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)
Linux網絡程式設計綜合運用之MiniFtp實作(五)

但是不是所有的系統都支援它,是以這裡我們自己來實作,其實作思路也比較簡單,規則如下:

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);
}      

下面編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

其中計算方式是從後往前的,是以可以将for循環進行修改一下變得更加簡單一些:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

 再次編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

這裡面是個坑,跟無符号整形有關,也就是這句話:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

這裡來列印一下i的變化就明白了:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

輸出如下:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

其原因是:

Linux網絡程式設計綜合運用之MiniFtp實作(五)
Linux網絡程式設計綜合運用之MiniFtp實作(五)

是以要解決此問題,很簡單,直接将無符号給去掉既可:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

再編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

⑥:将八進制的整形字元串轉換成無符号整型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給過濾掉,如下:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

而公式裡面應該是result*8+digit來進行計算,這裡用位操作來改寫,也就是result*8=result <<= 3,移位操作效率更加高效,是以最終代碼如下:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

下面則編寫測試代碼,來看下是否有效:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

編譯運作:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

下面我們手動來驗證下結果是否等于457:

711計算如下:

①、7*8+1=57

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

是以結果是正常的。

以上就是關于字元串需要用到的工具子產品,最後回到主程式來:

Linux網絡程式設計綜合運用之MiniFtp實作(五)

好了,下節繼續完善~~

轉載于:https://www.cnblogs.com/webor2006/p/4458899.html

繼續閱讀