Сравнение строк в C – strcmp

У меня возникли проблемы с сравнением строк в C (с которыми я довольно новичок). У меня есть сокет на этом серверном приложении, ожидающий приема данных от клиента. В этой части моей программы я хочу иметь возможность выполнить запрос MySQL на основе данных, полученных от клиента. Я хочу знать, когда полученные данные имеют значение «newuser», чтобы инициировать простую процедуру регистрации. Strcmp возвращает положительное значение 1, где я считаю, что мне нужно получить 0, потому что значения должны быть равны.

Исходный код:

//setup socket //loop and select structure to handle multiple connections if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) { // got error or connection closed by client if (nbytes == 0) { // connection closed printf("selectserver: socket %d hung up\n", i); } else { perror("recv"); } close(i); // bye! FD_CLR(i, &master); // remove from master set } else { char check[] = "newuser"; char fromUser[sizeof check]; strncpy(fromUser,buf, sizeof check); printf("length of fromUser: %d\n", sizeof fromUser); printf("length of check: %d\n", sizeof check); printf("message from user: %s\n", fromUser); printf("check = %s \n", check); int diff = strcmp(fromUser, check); printf("compare fromUser to check: %d\n", diff); if ( strcmp(fromUser, check) == 0) { printf("aha! new user"); } 

Выход:

 length of fromUser: 8 length of check: 8 newuser from user: newuser check = newuser compare fromUser to check: 

У меня такое чувство, что я неправильно обрабатываю входящий буфер или ошибочно копирую буфер.

strncpy копии не более – в этом случае – sizeof check bytes. Если нулевой байт не находится в этом диапазоне, он не копируется. Вероятно, вы получаете слово «newuser» как часть более длинного предложения, например «newuser blah blah», поэтому вам нужно разместить этот нуль самостоятельно

 strncpy(fromUser, buf, sizeof check); fromUser[sizeof check - 1] = '\0'; 

или используйте strlcpy , если они доступны.

Вот пример кода, который вы указали в своем вопросе (с удаленным кодом отладки):

 //setup socket //loop and select structure to handle multiple connections if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) { [... exception handling here ...] } else { char check[] = "newuser"; char fromUser[sizeof check]; strncpy(fromUser,buf, sizeof check); if ( strcmp(fromUser, check) == 0) { printf("aha! new user"); } 

Этот код неверен; вы потенциально копируете больше байтов из buf [], чем были получены. Это приведет к тому, что вы сравните с мусором (который случайно может совпасть с вашей строкой «newuser»). И, как говорили другие люди, у вас есть вторая ошибка из-за того, что NUL не завершает одну из ваших строк.

В этом случае я бы использовал memcmp (). Это похоже на strcmp (), но он принимает параметр длины, а не ожидает строки с нулевым завершением.

 //setup socket //loop and select structure to handle multiple connections if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) { [... exception handling here ...] } else { static const char check[] = "newuser"; const size_t check_len = sizeof(check) - 1; // exclude the NUL terminator if (nbytes >= check_len && memcmp(buf, check, check_len) == 0) { printf("aha! new user"); } 

PS Не связано напрямую, но recv () может завершиться неудачей, возвращая -1 с errno==EINTR . Это не является условием ошибки, вам просто нужно попробовать еще раз. Обычно это случается так редко, что люди уходят, не проверяя его, пока они не интегрируются с каким-то другим кодом, который использует сигналы, и внезапно их код случайно не срабатывает.

В приложении, основанном на select() , вы также должны настроить свои сокеты на неблокирующие, а затем проверить errno==EAGAIN и вернуться к select() в этом случае. Это может произойти, если стек TCP / IP получает поврежденный пакет - он считает, что у него есть пакет, поэтому select() скажет вам, что он доступен для чтения, только когда вы пытаетесь его прочитать, что стек TCP / IP выполняет расчет контрольной суммы и реализует он должен выбросить данные. Затем он либо блокируется (плохо), либо если он настроен на неблокирование, он возвращает -1 с errno==EAGAIN .

Я считаю, что проблема здесь (одна из проблем здесь) заключается в том, что fromUser (из-за того, как он создан) не завершается нулем.

Вы пропускаете символ «\ 0» в конце fromUser:

 ... strncpy(fromUser,buf, sizeof check); fromUser[strlen(check)] = '\0'; 

Требуются два изменения:

 char fromUser[sizeof check] = {'\0'}; //Make all null characters strncpy(fromUser,buf, sizeof check -1); //Last character is for null character. 

Этот код кажется выключенным:

 if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) { // your stuff } else { const char *pCheck = "newuser"; char *fromUser = new char[nbytes]; strncpy(fromUser, buff, nbytes); fromUser[nbytes] = '\0'; if(strcmp(fromUser,check)==0) // blah delete [] fromUser; } 

Заменить:

 char check[] = "newuser\0";