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”一词作为较长句子的一部分,例如“newuser blah blah”,因此您需要自己放置该 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”字符串匹配)。正如其他人所说,由于没有 NUL 终止您的一个字符串,您还有第二个错误。

在这种情况下,我会使用 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 堆栈收到损坏的数据包,就会发生这种情况 - 它认为它有一个数据包,所以select()会告诉您它是可读的,只有当您尝试读取它时,TCP/IP 堆栈才会进行校验和计算并意识到它必须丢弃数据。然后它会阻塞(坏),或者如果它设置为非阻塞,那么它将返回-1.errno==EAGAIN

于 2009-06-22T15:42:25.780 回答
2

我相信这里的问题(这里的问题之一)是 fromUser (由于它的创建方式)不是空终止的。

于 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

需要进行两项更改:

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 回答