c - Strtok() 随机返回 NULL

标签 c

我正在尝试创建一个通过发送两种类型的消息与服务器通信的客户端:

  1. 单词QUIT,用于与服务器通信以关闭连接。
  2. 具有以下语法的运算:operator first_operand secondary_operand。例如:+ 3 3- 5 6等(操作数必须为正整数,且只能有2个操作数)。

如果服务器收到一个操作,它会执行该操作并将结果返回给客户端。问题是我发送的第一个操作返回正确的结果,而接下来的操作随机工作(有时它们返回正确的结果,其他时候函数 strtok() 没有获取第二个操作数并且返回NULL...)。

这是客户端的代码,用于处理用户在提示符中编写的消息,并扫描消息以检查操作是否使用正确的语法编写(警告:代码编写为以一种极其不专业和不干净的方式)。

产生问题的代码部分位于while(1)内部。

#define MAXLENGTH 256

int main (int argc, char *argv[]) {
    int simpleSocket = 0;
    int simplePort = 0;
    int returnStatus = 0;
    char first[10], second[10]; 
    char* operator; 
    char buffer[MAXLENGTH] = ""; 
    char message[50]; 
    char terminationCommand[] = "QUIT\n"; 
    char space[2] = " "; 
    struct sockaddr_in simpleServer;

    if (3 != argc) {
        fprintf(stderr, "Usage: %s <server> <port>\n", argv[0]);
        exit(1);
    }

    /* create a streaming socket      */
    simpleSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (simpleSocket == -1) {
        fprintf(stderr, "Could not create a socket!\n");
        exit(1);
    } else {
        fprintf(stderr, "Socket created!\n");
    }

    /* retrieve the port number for connecting */
    simplePort = atoi(argv[2]);

    /* setup the address structure */
    /* use the IP address sent as an argument for the server address  */
    //bzero(&simpleServer, sizeof(simpleServer)); 
    memset(&simpleServer, '\0', sizeof(simpleServer));
    simpleServer.sin_family = AF_INET;
    //inet_addr(argv[2], &simpleServer.sin_addr.s_addr);
    simpleServer.sin_addr.s_addr=inet_addr(argv[1]);
    simpleServer.sin_port = htons(simplePort);

    /*  connect to the address and port with our socket  */
    returnStatus = connect(simpleSocket, (struct sockaddr *)&simpleServer, sizeof(simpleServer));

    if (returnStatus == 0) {
        fprintf(stderr, "Connect successful!\n\n");
    } else {
        fprintf(stderr, "Could not connect to address!\n");
        close(simpleSocket);
        exit(1);
    }

    /* get the message from the server   */
    returnStatus = read(simpleSocket, buffer, sizeof(buffer));

    if (returnStatus > 0) {
        printf("%s\n", &buffer[3]); 
    } else {
        fprintf(stderr, "Return Status = %d \n", returnStatus);
    }

    memset(&buffer, '\0', sizeof(buffer));

    printf("You can execute 2 commands:\n");
    printf("1. Operations ( +, -, *, /, % ) with the following syntax: operator + first operand + second operand.\n");
    printf("Example: + 5 2 \n");
    printf("2. Termination of the connection with the following syntax: QUIT + press Enter.\n");

    while(1) {
        printf("\nEnter a command:\n");
        fgets(message, 1000, stdin);

        // the if with the termination command works fine
        if (strcmp(message, terminationCommand) == 0) {
            if (send(simpleSocket, message, strlen(message), 0) < 0) {
                printf("Send failed.");
                return 1;
            }

            returnStatus = read(simpleSocket, buffer, sizeof(buffer));

            if (returnStatus > 0) {
                printf("%s\n", &buffer[4]); 
            } else {
                fprintf(stderr, "Return Status = %d \n", returnStatus);
            }

            close(simpleSocket); 
            exit(1); 
        }

        operator = strtok(message, space); 

        if (strcmp(operator, "+") == 0 || strcmp(operator, "-") == 0 || strcmp(operator, "/") == 0 || strcmp(operator, "%") == 0 || strcmp(operator, "*") == 0) {
            char *first_operand = strtok(NULL, space);

            if (first_operand != NULL) {
                if (strcmp(first_operand, "ANS") == 0)
                    strcpy(first, "ANS");
                else
                    strcpy(first, first_operand);

                printf("%s\n", operator);
                printf("%s\n", first);

                char *second_operand = strtok(NULL, space);

                printf("%s\n", second_operand);

                if (second_operand != NULL && strtok(NULL, space) == NULL && (atoi(first) > 0 || strcmp(first, "ANS") == 0)) {
                    if (strcmp(second_operand, "ANS\n") == 0)
                        strcpy(second, "ANS");
                    else {
                        strcpy(second, second_operand);
                    }

                    if (atoi(second) > 0 || strcmp(second, "ANS") == 0) {
                        printf("OK\n");

                        char operation[] = ""; 

                        strcat(operation, operator); 
                        strcat(operation, " ");
                        strcat(operation, first); 
                        strcat(operation, " ");
                        strcat(operation, second); 

                        if (send(simpleSocket, operation, strlen(operation), 0) < 0) {
                            printf("Send failed.");
                            return 1;
                        }

                        returnStatus = read(simpleSocket, buffer, sizeof(buffer));

                        if (returnStatus > 0) {
                            printf("%s\n", buffer); 
                        } else {
                            fprintf(stderr, "Return Status = %d \n", returnStatus);
                        }
                    }
                }         
            }
        }

        // after everything I reset the buffers I use to memorize the message and the elements of the message
        memset(&buffer, '\0', sizeof(buffer));
        memset(&first, '\0', sizeof(first));
        memset(&second, '\0', sizeof(second));
        memset(&message, '\0', sizeof(message));
        memset(operator, '\0', sizeof(operator));
    }
}

有人能告诉我为什么第二个 strtok() 90% 的时候都表现得很奇怪吗?我做错了什么?

最佳答案

您的程序存在多个问题:

您发送换行符终止的消息,并且您假设另一端的读取将准确返回对方发送的字节,这对于 TCP/IP 通信来说是一个错误的假设,仅返回顺序接收的字节数是有保证的,但消息可以在途中分割并以与发送顺序不同的 block 形式接收。您应该将套接字读入缓冲区,并且仅在收到换行符后才处理它。

就您的情况而言,还有另一个更紧迫的问题:您读取数据的缓冲区不是 null 终止的,因此您不应将其传递给标准 C 函数,例如 strtok().

关于c - Strtok() 随机返回 NULL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52139211/

相关文章:

c - `size_t`是标准库的一部分,还是C语言本身的一部分?

c - 简单的 PAM 示例

c - C语言中的DCCP套接字编程

c++ - C/C++ 中两个字符的总和

c - 带有 struct hack 的结构数组

c - 快速排序功能不起作用(在 c 中)

在 C 中分配二维堆数组时出现一致的段错误

c - C 中的梯形黎曼和

c - MinGW 和 MSVC 之间的链接困境(未定义引用)。 MinGW 失败 MSVC 工作

c - 从c程序中读取文件中的行得到错误的输出