如何按C中的IP地址对传输进行分组以计算传输速率?

时间:2013-11-08 20:16:39

标签: c

我是C的初学者,我遇到了一个有趣的问题。

我正在捕获端口80上的所有传出数据包,我想计算每个IP的传输速度。但问题是我不知道如何对这些IP地址进行分组,在PHP中我可以通过IP创建数组和索引条目并搜索数组,如果IP索引已经存在,则传输更新值字节,然后将其除以经过的秒数,我有B / s的传输速度。但在C中,我不能这样做。

建议我如何实现我的问题,因为现在我只能计算整体传输速度。

  t2 = time(0);
  time_elapsed = (int) (t2-t1);
  if(time_elapsed > 0) {
    bytes += Size;
    //packets size SUM from all IP addresses, which is incorrect

    printf("IP: %s | Size: %d\n\n", inet_ntoa(dest.sin_addr), Size);
  }

输出

IP: 77.236.192.100 | Size: 4434

IP: 89.176.81.106 | Size: 43854

IP: 89.176.81.106 | Size: 20494

IP: 89.176.81.106 | Size: 24874

IP: 77.236.192.100 | Size: 7354

IP: 89.176.81.106 | Size: 39474

IP: 89.176.81.106 | Size: 16114

3 个答案:

答案 0 :(得分:2)

在C中,您可以使用带有指针的链式节点,也称为队列,列表或堆栈(取决于其结构如何)。我有一个可能适合您的代码:

struct _ip_map_node {
    struct _ip_map_node* next;
    unsigned long ip;
    unsigned long transfered;
    unsigned long time;
};
typedef struct _ip_map_node ip_map_node;

ip_map_node* update_or_create_ip_map_node(ip_map_node** queue, unsigned long ip, unsigned long transfered) {
    ip_map_node* node = *queue;
    while (node) {
        if (node->ip == ip) {
            node->transfered += transfered;
            return node;
        }
        node = node->next;
    }
    node = malloc(sizeof(ip_map_node));
    node->next = *queue;
    *queue = node;

    node->ip = ip;
    node->transfered = transfered;
    node->time = time(NULL);

    return node;
}

void remove_ip_map_node(ip_map_node** queue, unsigned long ip) {
    ip_map_node* last = NULL;
    ip_map_node* curr = *queue;
    while (curr) {
        if (curr->ip == ip) {
            if (last)
                last->next = curr->next;
            else
                *queue = curr->next;

            free(curr);
            break;
        }
        last = curr;
        curr = curr->next;
    }
}

ip_map_node* my_ip_map = NULL;

我做了一些更改以最适合您的目的,并没有检查是否编译,如果您无法搞清楚我可以帮助您。

这基本上就是你如何使用它:你有一个名为my_ip_map的IP列表,默认为空。

您可以在其中创建元素或使用以下内容进行更新:

ip_map_node* node = update_or_create_ip_map_node(&my_ip_map, dest.sin_addr.s_addr, data_size);

其中data_size是此时转移到该IP的字节数。它将自动汇总到之前发送到同一IP的金额。

node具有以下属性:

node->ip; // The IP in numeric format, use inet_ntoa() to transform it
node->transfered; // The amount that was transfered to that IP so far
node->time; // the time(NULL) when the first packet was sent to this IP

您现在可以使用node->transfered / (time(NULL) - node->time)获得传输速度 - 请小心,因为除以零会崩溃。

如果您想每隔几秒钟重置一次此节点,您可以使用:

node->transfered = 0;
node->time = time(NULL);

或者删除它:

remove_ip_map_node(&my_ip_map, dest.sin_addr);

要运行列表中的所有IP,例如:

ip_map_node* node = my_ip_map;
while(node) {
    printf("%s, %d\n", inet_ntoa(*(struct in_addr *)&node->ip), node->transfered);
    node = node->next;
}

出于性能原因,它的结构为堆栈(最后添加的元素首先出现)。

答案 1 :(得分:0)

C ++ 中,如果您需要一个可以通过包含IP的字符串访问的关联容器,则可以使用map< string, float >类型的map container(当然,如果你使用字符串存储IP)

然后,您只需执行yourMapName[IPaddress]

即可访问这些元素

如果您需要在 C 中执行此操作,则需要执行包含IP地址的struct(如果它是纯C,您可能会使用char*,然后你需要做一个这样的结构数组和一个函数,它在数组中搜索给定unsigned int的结构并添加到int中,或者添加一个新的条目数组。

如果您需要使结构数组灵活(因为您不知道要连接多少个IP),您需要学习如何使用char*malloc C函数

因此,如果你没有坚持使用纯C - 那么在C ++中这样做会更直接。只是一个提示,这是你的选择。

答案 2 :(得分:0)

不要自己实现,使用C中可用的大量库之一。使用glib的例子:

#include <glib.h>
#include <stdio.h>

unsigned lookup(GHashTable *dict, const char *key)
{
    return GPOINTER_TO_UINT(g_hash_table_lookup(dict, key));
}

void accumulate(GHashTable *dict, char *key, unsigned increment)
{
    unsigned value;

    value = lookup(dict, key);
    g_hash_table_insert(dict, key, GUINT_TO_POINTER(value + increment));
}

int main(void)
{
    GHashTable *ip;

    ip = g_hash_table_new(g_str_hash, g_str_equal);
    accumulate(ip, "10.1.1.1", 0);
    accumulate(ip, "10.10.10.10", 2);
    accumulate(ip, "10.1.1.1", 2);
    accumulate(ip, "10.1.1.1", 3);
    accumulate(ip, "10.2.2.2", 10);

    printf("%u\n", lookup(ip, "10.1.1.1"));
    printf("%u\n", lookup(ip, "10.10.10.10"));
    printf("%u\n", lookup(ip, "10.2.2.2"));

    g_hash_table_unref(ip);

    return 0;
}

输出:

$ ./hash 
5
2
10

https://developer.gnome.org/glib/2.38/glib-Hash-Tables.html