【问题标题】:Server thinks 2 clients with different IPs are the same 1 client (C Socket Programming)服务器认为 2 个不同 IP 的客户端是同一个客户端(C 套接字编程)
【发布时间】:2017-12-03 16:44:08
【问题描述】:

我有一台服务器,它应该允许一个客户端一次连接、执行命令然后关闭。服务器保留“当前连接的”IP 地址的数组列表,以便知道从谁那里接受命令。 问题是我有两个运行在相似 IP 地址上的客户端被视为同一个客户端。

示例: 客户端 A 的 IP 地址为 255.255.255.153。我告诉它连接,一切正常。 客户端 B 的 IP 地址为 255.255.255.156。我告诉它连接,服务器说它已经连接。

我的 strcmp 不正确吗?是别的吗?请帮忙。

// Variable Declarations

int SIZE = 10; // Max number of agents
char *agents[SIZE], // List of current connections
     *times[SIZE]; // List of connection times
char buffer[MAXBUF];
int bytes_read = 0;
int total_bytes_read = 0;
int found = 0, // Bool flag
    i;
struct tm  ts;
struct timeval connected[SIZE],
               current,
               difference;
       time_t TIME;

// Initialize array to NULL
for(i = 0; i < SIZE; i++) {
    agents[i] =  NULL;
}

// Infinite Loop
while (true) {
    struct sockaddr_in client;
    int clientSocket;
    socklen_t clientLength = sizeof(client);
    memset(&client, 0, clientLength);
    clientSocket = accept(sd, (struct sockaddr *)&client, &clientLength);

    memset(buffer,0,MAXBUF);
    bytes_read = read(clientSocket, buffer, MAXBUF);
    if (bytes_read < 0)
        break;
    fprintf(stdout,"\nRead %d bytes: [%s]\r\n", bytes_read,buffer);

    char *connectedIP = inet_ntoa(client.sin_addr);

    // Option 1:
    if ((strcmp(buffer, "#JOIN")) == 0) { // Join list of connected agents
        found = 0;

        // Get current time for log
        TIME = time(NULL);
        ts = *localtime(&TIME);

        // Print message to log
        char buf[80];
        strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
        fprintf(log, "%s: Received a \"#JOIN\" action from agent \"%s\"", buf, connectedIP);
        fprintf(log, "\n\n");
        fflush(log);

        printf("\n%s Joining", connectedIP);
        fflush(stdout);
        // Handle #JOIN request appropriately
        for (i = 0; i < SIZE; i++) {
            printf("\nAgent[%d] == %s", i, agents[i]);

            if (agents[i] == NULL) {

            }
            else if (strcmp(agents[i], connectedIP) == 0){ // Agent found in list
                found = 1;

                printf("\n%s is equal to %s", agents[i], connectedIP);
                fflush(stdout);

                // Write to agent
                char response[] = "#ALREADY MEMBER";
                write (clientSocket, response, strlen(response));

                // Get time for log
                TIME = time(NULL);
                ts = *localtime(&TIME);

                // Write to log
                char buf[80];
                strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
                fprintf(log, "%s: Responded to agent \"%s\" with \"#ALREADY MEMBER\"", buf, connectedIP);
                fprintf(log, "\n\n");
                fflush(log);
                i = SIZE;
            }
        }
        if (found == 0) { // Save IP to list/queue
            for(i = 0; i < SIZE; i++) {
                if (agents[i] == NULL) {

                    // Save IP to array
                    agents[i] = connectedIP;

                    printf("\nagents[%d] = %s\n", i, connectedIP);
                    fflush(stdout);

                    // Save time to arrays
                    gettimeofday(&connected[i], NULL);
                    TIME = time(NULL);
                    times[i] = TIME;
                    ts = *localtime(&TIME);

                    // Write to log
                    char buf[80];
                    strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
                    fprintf(log, "%s: Responded to agent \"%s\" with \"#OK\"", buf, connectedIP);
                    fprintf(log, "\n\n");
                    fflush(log);

                    // Write to agent
                    char response[] = "#OK";
                    write (clientSocket, response, strlen(response));
                    i = SIZE;
                }
            }
        }
        memset(&client, 0, clientLength);
    }

【问题讨论】:

  • 你没有展示agents数组是如何定义的,AFAICS。如果您已正确定义它并将 IPv4 地址存储为字符串,strcmp() 应该没问题。但是您需要允许 16 个字节用于存储每个地址; 3 个单位的“192”。和“192\0”之一。因此,很大程度上取决于您未显示的代码。请阅读有关如何创建 MCVE (minimal reproducible example) 的信息。你展示的不是 MCVE。
  • 添加了“代理”声明,对评论感到抱歉。修好了。
  • 你存储agents[i] = connectedIP; 再一次,一个未声明的变量,但你可能为所有代理使用相同的空间,所以如果你遍历连接的代理,打印名称,你会发现它们都一样。我希望那里有strdup(connectedIP) 之类的东西。但它仍然不是 MCVE,因此人们仍然不方便尝试帮助您。
  • conectedIP 的定义显示在char *connectedIP = inet_ntoa(client.sin_addr); 我会看看strdup
  • 我还建议不要仅根据他们的 IP 地址来识别您的客户。从一个 IP 打开多个连接可能有正当的理由,例如 NAT(可能使用虚拟机)、测试场景以及您的高级用户想出的任何其他内容。 IP地址作为唯一身份验证者也很糟糕。

标签: c sockets server


【解决方案1】:

inet_ntoa() 的 POSIX 规范包括以下信息:

inet_ntoa() 函数应将 in 指定的 Internet 主机地址转换为 Internet 标准点表示法中的字符串。

inet_ntoa() 函数不必是线程安全的。

inet_ntoa() 的 Linux 手册页更明确地说明了它的行为方式以及 POSIX 警告在该平台上的含义:

inet_ntoa() 函数将以网络字节顺序给出的 Internet 主机地址转换为 IPv4 点分十进制表示法的字符串。该字符串在静态分配的缓冲区中返回,后续调用将覆盖该缓冲区。

正如我在comment 中指出的那样(是的,该评论的第一部分并不准确——iPhone 应用程序上的代码很难阅读):

...但是您可能会为所有代理使用相同的空间,因此如果您遍历连接的代理,打印名称,您会发现它们都是相同的。我希望那里有 strdup(connectedIP) 之类的东西。

这意味着由于您的代码只是将inet_ntoa() 返回的指针保存在agents 数组中,因此该数组始终包含最后查找的主机。您必须从inet_ntoa() 获取结果副本并保存,并管理存储。最简单的方法是使用strdup() 进行复制,但您必须记住在连接关闭时释放它。

使用strdup() 或等效机制应该可以解决您的直接问题。小心内存泄漏。

【讨论】:

  • 我最终做了strdup(inet_ntoa(client.sin_addr)),它运行良好。非常感谢。我认为将结果存储到connectedIP 会保存实际的字符串,而不仅仅是一个指针。再次感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-09
  • 1970-01-01
  • 2015-12-12
  • 1970-01-01
  • 2019-03-17
  • 2023-03-18
相关资源
最近更新 更多