2009-06-22 3 views
0

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

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

//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: 

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

+1

Вы не регистрируете значение fromUser, а только его длину. – Tom

ответ

6

strncpy копии на большинстве - в данном случае - sizeof проверки байт. Если нулевой байт не находится в этом диапазоне, он не копируется. Вы, вероятно, получаете слово «NEWUSER» как часть более длинного предложения, как «новый_пользователь-бла-бла», так что вам нужно место, NUL себе

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

или использовать strlcpy, если таковые имеются.

+0

+1 для упоминания strlcpy – Tom

2

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

2

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

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

Разве это не будет sizeof (check) - 1? – DeadHead

-1

Заменить:

char check[] = "newuser\0"; 
+1

двойные кавычки производят строку с нулевым завершением сами по себе, не так ли? – cube

+1

"" литералы неявно завершены NUL. Добавление другого NUL явно не помогает здесь. – laalto

1

Два необходимых изменений:

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

Этот код кажется от:

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

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

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

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

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

Смежные вопросы