【问题标题】:Server to Validate Credentials (Socket Programming)验证凭证的服务器(套接字编程)
【发布时间】:2015-03-21 13:40:19
【问题描述】:

首先,我是 c 的初学者。该程序模拟客户端通过端口 8000 上的 telnet 连接到的服务器,并为其提供用户名和密码,然后服务器对其进行验证。我成功地从客户端获取了用户名,但我在验证它时遇到了一些问题。我需要将用户名与凭据列表进行比较,但它似乎不起作用。这是我到目前为止编写的代码...

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

int main()
{

    char * credentialsList[7][2] = {{"Alice","abcdef"}, {"Bob","1234567"}, {"Cindy","qwerty"}, {"David","abababab"}, {"Eve", "cdefgh"}, {"Frank","7654321"}, {"George", "12341234"}};
    int serverSocket=socket(AF_INET, SOCK_STREAM, 0);
    int new_socket, i;
    char *message, client_message[10];
    struct sockaddr_in server, client;
    server.sin_family =  AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(8000);
    bind(serverSocket, (struct sockaddr *)&server, sizeof(server));
    listen(serverSocket,2);
    int c = sizeof(struct sockaddr_in);
    new_socket = accept(serverSocket, (struct sockaddr *)&client, (socklen_t*)&c);
    message = "Welcome! You Are Now Connected To The Server.\n\n";
    write(new_socket, message, strlen(message));
    message = "Please Enter A Valid Username: ";
    write(new_socket, message, strlen(message));
    recv(new_socket, client_message, 10, 0);
    for (i=0; i<7; i++)
    {
        if (strcmp(credentialsList[i][0], client_message) == 0)
        {
            // TO DO
            puts("GOT YOU");
        }
    }
    return 0;
}

提前致谢:)

【问题讨论】:

  • 不清楚接收到的数据是什么样子的。它有空终止符吗?
  • @ForceBru 代码已编辑!
  • 我的意思是,你能举一个收到的数据的例子吗?
  • 一个例子是用户名“Alice”@ForceBru

标签: c string sockets multidimensional-array


【解决方案1】:

在 C 编程中,字符串将由 NULL 字符终止(即;'\0',其十六进制值为 0x00)。所以@juhist 说使用 NULL 字符结束接收到的数据,这里我将简单地用 NULL 字符清除整个 client_message[] 数组,这样如果我们收到,假设 8 个字符,第 9 个字符将由 NULL 字符终止确保这是一个字符串

memset(client_message,0x00,sizeof(client_message));
recv(new_socket, client_message, 10, 0);
    for (i=0; i<7; i++)
    {
        if (strcmp(credentialsList[i][0], client_message) == 0)
        {
            // TO DO
            puts("GOT YOU");
        }
    }

【讨论】:

  • 是的。但仍然收到的值与二维数组中的任何值都不匹配。例如,用户名“Alice”。
  • 添加 puts(client_message);在 recv() 函数之后,是在屏幕上给你预期的消息(这只是打印接收到的数据)
  • 另外,client_message 的长度必须最大为 9(即使您已声明 10 ,也必须为 NULL 字符 0x00 保留一个元素,否则请尝试增加 client_message 数组大小,如 client_message[50 ])
  • 我已经更新了帖子,可能是因为那个 char 数组声明
  • char * credentialsList 中删除* 会产生错误。
【解决方案2】:

您的问题是您隐含地假设接收到的数据具有 '\0' 终止符。网络协议通常不是这种情况。此外,您如何知道是否收到了完整的用户名?现在它只是读取 TCP 段中有多少字节可用,并且您不应该让您的程序依赖于 TCP 分段详细信息。此外,您忽略了 recv() 系统调用的返回值,它可能读取 10 个字节或可能读取更少的字节。

我建议创建一个函数 recvall() 而不是 recv(),它会在循环中调用函数 recv(),通过 re-recv()'ing 来正确处理部分读取以获取更多数据。

一种选择是将用户名的长度作为网络字节顺序的 32 位二进制整数传输,然后使用 recvall() 接收用户名的 4 字节长度,然后使用 recvall()您想读取的字节数。写入数据的程序显然也需要改变,首先将用户名的长度写入网络字节顺序的 32 位二进制整数。

还有其他可能的选择。例如,您可以使用 '\n' (即换行符)来终止用户名,但这需要使用 1 字节缓冲区在循环中调用 recv() ,这是非常低效的,或者在顶部使用您自己的缓冲解决方案接收()。因此,我的建议是将用户名的长度作为网络字节顺序的 32 位整数发送;这要简单得多。

一般来说,您应该检查所有系统调用的返回值。除了忽略 recv() 系统调用的返回值之外,您还忽略了 write() 系统调用的返回值。这是不好的做法。

为了保持一致性,我建议使用 recv() 和 send() 或 write() 和 read(),而不是像 recv() 和 write() 这样的混合函数。

我还强烈建议在您的代码中添加空行来构建它。现在没有空行很难阅读。

【讨论】:

  • 感谢您的回答,非常感谢。但我无法真正理解你所说的。我是 c 和套接字编程的初学者。因此,如果您能详细说明需要更改的内容以及需要在代码中添加的内容,我将不胜感激。
猜你喜欢
  • 1970-01-01
  • 2022-06-16
  • 1970-01-01
  • 2011-10-01
  • 2014-03-24
  • 2013-01-30
  • 1970-01-01
  • 2014-03-01
  • 2013-11-13
相关资源
最近更新 更多