strcmp的坑

strcmp的坑

下面的程序是通過對輸入進行判斷,來決定輸出內容的。

# include<stdio.h>
#include<string.h>
int main(){
    printf("請輸入: ");
    char buf[1024];
	//這裏想通過判斷輸入是否是quit來決定是否完成閱讀
    if (fgets(buf, sizeof(buf), stdin) != NULL && (strcmp(buf, "quit"))){
        printf("歡迎閱讀本文章\n");
        for (int i = 0;i < 1024;i++){
        	//打印每個字符的內容
            printf("%d ",buf[i]);
        }
    }
    else{
        printf("您已經閱讀完成本文了,點一下關注哈\n");
    }
    printf("\n");
}

但是當輸入quit的時候,沒有走else流程。運行結果居然是是第一個輸出。通過打印出來的buf中的字符來看,發現多了個10,因此buf比"quit"要大,也就是strcmp的返回結果是10,爲真,所以會走if的流程。
在這裏插入圖片描述

實戰抓包

重寫客戶端

通過上面的分析,可以看出,在這篇文章中,想通過輸入quit來關閉socket的實現是有問題的。可以通過另一個函數完美解決這個問題-strncmp。

原型:strcmp(str1,str2);
功能:比較兩個字符串,如果兩個字符串相等,則返回0;若str1大於str2(對於大於的理解,是指從兩個字符串的第一個字符開始比較,若兩個字符相同,則繼續比較,若發現兩個字符不相等,且str1中該字符的ASCII碼大於str2中的,則表示str1大於str2),返回一個正數(這個正數不一定是1);若str1小於str2,返回一個負數(不一定是-1);若字符串str1的長度大於str2,且str2的字符與str1前面的字符相同,則也相對於str1大於str2處理
原型2:strncmp(str1,str2,n);
功能2:比較兩個字符串的前n個字符

重新寫下客戶端的代碼

/*************************************************************************

> File Name: client.c

> Author: 無情劍客

> Mail: [email protected]

> Created Time: 2020年07月01日 星期三 21時44分37秒

 ************************************************************************/

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<sys/types.h>

#include<sys/socket.h>

#include<unistd.h>

#include<netinet/in.h>

#define PORT 6666

#define MAXDATASIZE 2048

int main(int argc, char *argv[])

{

    if(argc != 2)

    {

        fprintf(stderr, "請您輸入ip地址!\n");

        exit(1);

    }

    int sockfd;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    const char *server_ip = argv[1]; //從命令行獲取輸入的ip地址,此處沒有對ip地址進行檢驗

    struct sockaddr_in serveraddr;

    bzero(&serveraddr, sizeof(serveraddr));

    serveraddr.sin_family = AF_INET;

    serveraddr.sin_port = htons(PORT);

    inet_pton(AF_INET, server_ip, &serveraddr.sin_addr);

    connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));

    printf("=====================服務器鏈接成功=====================\n");

    char buf[MAXDATASIZE];

    memset(buf, 0 ,  sizeof(buf));

    printf("請輸入: ");
	//判斷輸入的內容是否是quit,如果輸入quit,則關閉連接
    while(fgets(buf, sizeof(buf), stdin) != NULL && (strncmp(buf, "quit", 4)))

    {

        send(sockfd, buf, sizeof(buf), 0);

        memset(buf, 0, sizeof(buf));

        recv(sockfd, buf, sizeof(buf), 0);

        printf("服務器說: ");

        fputs(buf, stdout);

        memset(buf, 0, sizeof(buf));

        printf("請輸入: ");

    }

    printf("客戶端將要被關閉,下次再見\n");

    close(sockfd);

    return 0;

}

服務器端代碼可參考這篇文章

完整抓包

開啓wireshark,來進行一次完整的抓包。

在這裏插入圖片描述因爲服務iqi地址是127.0.0.1。本地環回地址,所以使用Loopback:lo接口。如果不是本地的服務器,需要選擇相應的網卡接口。下面兩個圖展示了TCP的三次握手和四次揮手。
在這裏插入圖片描述
在這裏插入圖片描述

公衆號

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章