c -strcmp의 문자열 비교
-
06-07-2019 - |
문제
나는 C에서 문자열을 비교하는 데 어려움을 겪고있다 (내가 상당히 새로운). 이 서버 애플리케이션에 소켓이 클라이언트의 데이터를 수락하기 위해 기다리고 있습니다. 내 프로그램 의이 특정 부분에서는 클라이언트로부터받은 데이터를 기반으로 MySQL 쿼리를 실행할 수 있기를 원합니다. 수신 된 데이터에 간단한 등록 절차를 시작하기 위해 "NewUser"의 값이 언제인지 알 수 있습니다. STRCMP는 값이 같아야하기 때문에 0을 받아야한다고 생각하는 양의 1 값을 반환합니다.
소스 코드:
//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
바이트를 점검하십시오. NUL 바이트가 해당 범위에 있지 않으면 복사되지 않습니다. 당신은 아마도 "Newuser blah blah"와 같은 더 긴 문장의 일부로 "Newuser"라는 단어를 얻을 것입니다.
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"문자열과 일치 할 수 있습니다). 그리고 다른 사람들이 말했듯이, 당신은 당신의 줄 중 하나를 종료하지 않기 때문에 두 번째 버그가 있습니다.
이 경우 memcmp ()를 사용합니다. 이것은 strcmp ()와 같지만 NUL이 종결 된 스트링을 기대하는 대신 길이 매개 변수가 필요합니다.
//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");
}
추신은 직접 관련이 없지만 recv () 돌아와서 실패 할 수 있습니다 -1
~와 함께 errno==EINTR
. 이것은 오류 조건이 아니며 다시 시도하면됩니다. 일반적으로 이것은 사람들이 신호를 사용하고 갑자기 코드가 무작위로 실패하는 다른 코드와 통합 될 때까지 사람들이 확인하지 않고 도망 갈 수 없습니다.
안에 select()
-기반 앱, 소켓을 차단하지 않은 상태로 설정 한 다음 확인해야합니다. errno==EAGAIN
, 그리고 다시 돌아갑니다 select()
이 경우. TCP/IP 스택에 손상된 패킷을받는 경우 발생할 수 있습니다. 패킷이 있다고 생각합니다. select()
읽을 수 있다고 말할 것입니다. TCP/IP 스택이 체크섬 계산을 수행하고 데이터를 버려야한다는 사실을 읽으려고 할 때만 가능합니다. 그런 다음 블록 (나쁜)이거나 차단되지 않은 상태로 설정되면 반환됩니다. -1
~와 함께 errno==EAGAIN
.
여기서 문제가있는 문제는 (여기서 문제 중 하나) FromUser (생성 방식으로 인해)가 널 종료되지 않았다는 것입니다.
Fromuser의 끝에서 ' 0'숯을 그리워합니다.
...
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";