C 验证凭据的服务器(套接字编程)

C 验证凭据的服务器(套接字编程),c,string,sockets,multidimensional-array,C,String,Sockets,Multidimensional Array,首先,我是c语言的初学者。此程序模拟客户端通过端口8000上的telnet连接到的服务器,并为其提供用户名和密码,服务器验证它们。我成功地从客户端获取用户名,但在验证时遇到一些问题。我需要将用户名与凭据列表进行比较,但它似乎不起作用。这是我到目前为止写的代码 #include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include &

首先,我是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;
}
#包括
#包括
#包括
#包括
#包括
int main()
{
char*credentialsList[7][2]={{{“Alice”、“abcdef”}、{“Bob”、“1234567”}、{“Cindy”、“qwerty”}、{“David”、“Abababababab”}、{“Eve”、“cdefgh”}、{“Frank”、“7654321”}、{“George”、“12341234”};
int serverSocket=socket(AF_INET,SOCK_STREAM,0);
int新_插座,i;
char*消息,client_消息[10];
服务器、客户端中的结构sockaddr_;
server.sinu family=AF\u INET;
server.sin\u addr.s\u addr=INADDR\u ANY;
server.sin_port=htons(8000);
绑定(serverSocket,(struct sockaddr*)&server,sizeof(server));
监听(serverSocket,2);
int c=sizeof(结构sockaddr_in);
new_socket=accept(serverSocket,(struct sockaddr*)和client,(socklen_t*)和c);
message=“欢迎!您现在已连接到服务器。\n\n”;
写入(新的_套接字、消息、strlen(消息));
message=“请输入有效的用户名:”;
写入(新的_套接字、消息、strlen(消息));
recv(新的_套接字,客户端_消息,10,0);

对于(i=0;i您的问题是,您隐式地假设接收到的数据有一个“\0”终止符。网络协议通常不是这样。此外,您如何知道是否接收到完整的用户名?现在它只读取TCP段中有多少字节可用,并且您不应该使您的程序依赖于TCP段a此外,您正在忽略recv()系统调用的返回值,该系统调用可能读取10个字节,也可能读取更少的字节

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

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

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

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

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


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

在C编程中,字符串将以空字符(即“\0”,其十六进制值为0x00)结尾。因此@juhist说要使用空字符结束接收的数据,这里我只需清除整个客户端消息[]数组中包含空字符,因此,如果我们接收到8个字符,则假设第9个字符将由空字符终止,以确保这是一个字符串

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");
        }
    }
memset(客户端消息,0x00,sizeof(客户端消息));
recv(新的_套接字,客户端_消息,10,0);

对于(i=0;iIt不清楚接收到的数据是什么样子。它是否有空终止符?@ForceBru Code Edited!我的意思是,您能给出一个接收到的数据的示例吗?一个示例是用户名“Alice”@ForceBruThanks谢谢你的回答,我很感激。但是我不能真正理解你的意思。我是c和socket编程的初学者。因此,如果你能详细说明需要更改的内容以及需要在代码中添加的内容,我将非常感谢。是的。但收到的值仍然与任何值都不匹配在2d数组中。例如,用户名“Alice”。add put(client_message);在recv()函数之后,是否会在屏幕上显示预期的消息(这只是打印接收到的数据)以及client_message的最大长度必须为9(尽管您声明了10,但必须为空字符0x00保留一个元素,否则请尝试增加客户端消息数组大小,如客户端消息[50])我更新了帖子,可能是因为该字符数组声明从
char*credentialsList
中删除
*
会产生错误。