0

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:

着信バッファを正しく処理していないか、誤ってバッファをコピーしているように感じます。

4

7 に答える 7

6

strncpyコピーするのはせいぜい - この場合 -sizeofチェック バイトです。nul バイトがその範囲にない場合、コピーされません。おそらく、「newuser blah blah」のような長い文の一部として「newuser」という単語を取得しているので、その nul を自分で配置する必要があります。

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

またはstrlcpy、利用可能な場合は を使用します。

于 2009-06-22T15:27:53.110 に答える
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」文字列と一致する可能性があります)。そして、他の人が言ったように、文字列の 1 つを NUL で終了しないために、2 つ目のバグがあります。

この場合、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");
    }

PS 直接関係はありませんが、recv()は を返すこと-1で失敗する可能性がありerrno==EINTRます。これはエラー状態ではありません。再試行する必要があります。通常、これはめったに発生しないため、シグナルを使用する他のコードと統合し、突然コードがランダムに失敗するまで、人々はそれをチェックせずに逃げます。

ベースのアプリでは、select()ソケットをノンブロッキングに設定してから をチェックしerrno==EAGAIN、その場合は に戻る必要がありselect()ます。これは、TCP/IP スタックが破損したパケットを受信した場合に発生する可能性があります。TCP/IP スタックはパケットがあるselect()と認識しているため、読み取り可能であることがわかります。TCP/IP スタックがチェックサム計算を行い、それが必要であることを認識したのは、読み取りを試みたときだけです。データを捨てる。-1その後、ブロックする (悪い) か、非ブロックに設定されている場合はを返しerrno==EAGAINます。

于 2009-06-22T15:42:25.780 に答える
2

ここでの問題 (ここでの問題の 1 つ) は、fromUser (作成方法による) が null で終了していないことだと思います。

于 2009-06-22T15:26:47.013 に答える
2

fromUser の最後に '\0' 文字がありません:

...
strncpy(fromUser,buf, sizeof check);
fromUser[strlen(check)] = '\0';
于 2009-06-22T15:26:55.843 に答える
1

2 つの変更が必要です。

char fromUser[sizeof check] = {'\0'}; //Make all null characters
strncpy(fromUser,buf, sizeof check -1); //Last character is for null character.
于 2009-06-22T15:31:27.720 に答える
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;
}
于 2009-06-22T15:36:04.997 に答える
-1

と置換する:

char check[] = "newuser\0";
于 2009-06-22T15:29:11.437 に答える