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

时间:2015-03-21 13:40:19

标签: c string sockets multidimensional-array

首先,我是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;
}

提前致谢:)

2 个答案:

答案 0 :(得分:0)

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

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

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

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

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

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

我还非常建议在代码中添加空白行来构建它。现在很难读,没有空行。

答案 1 :(得分:0)

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

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");
        }
    }