线程中的链表



我写了一个C脚本,我尝试接收NTP数据包并将它们添加到一个链表中,然后根据每个IP接收的NTP数据包数量对其进行排序。

使用checkInList()命令似乎在main()的测试中工作良好,但在recievethread()中调用时比较错误的ip。

预期输出:

[ (187.1.160.84:31) (255.255.255.255:400) (8.8.8.8:0) (192.168.2.1:0)  ]

意味着我们从8.8.8.8接收到400个数据包,以此类推。

实际产出:

[ (187.1.160.84:431) ]

发生的情况是数据包计数不断增加,但ip只是更改为最近的,而不是添加一个新的。

代码:

struct node  
{
    char *ip;
    int count;
    struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
void printInList()
{
    struct node *ptr = head;
    printf("n[ ");
    //start from the beginning
    while(ptr != NULL)
    {
        printf("(%s:%d) ", ptr->ip, ptr->count);
        ptr = ptr->next;
    }
    printf(" ]");
}

int length()
{
    int length = 0;
    struct node *current;
    for(current = head; current != NULL; current = current->next)
    {
        length++;
    }
    return length;
}
void sort(){
    int i, j, k, tempKey, tempData ;
    struct node *current;
    struct node *next;
    int size = length();
    k = size ;
    for ( i = 0 ; i < size - 1 ; i++, k-- ) {
        current = head ;
        next = head->next ;
        for ( j = 1 ; j < k ; j++ ) {
            if ( current->count < next->count ) {
                tempData = current->count ;
                current->count = next->count;
                next->count = tempData ;
                tempKey = current->ip;
                current->ip = next->ip;
                next->ip = tempKey;
            }
            current = current->next;
            next = next->next;                        
        }
    }
}
void insertInList(char *ipaddr, int count)
{
#ifdef DEBUG
    printf("Inserting: %s:%dt", ipaddr, count);
#endif
   //create a link
   struct node *link = (struct node*) malloc(sizeof(struct node));
   link->ip = ipaddr;
   link->count = count;
#ifdef DEBUG
    printf("Inserted: %s:%dt", link->ip, link->count);
#endif
   //point it to old first node
   link->next = head;
   //point first to new first node
   head = link;
}
int checkInList(const char *string)
{
    /* 
    If 1 returned means we found it
    If 0 Means we didnt find it 
    */
    struct node *ptr = head;
    //start from the beginning
    while(ptr != NULL)
    {
#ifdef DEBUG
        printf("Comparing %s and %-20s", ptr->ip, string);
#endif
        if(strcmp(ptr->ip, string) == 0) {
#ifdef DEBUG
            printf("Adding count: %s->%dn", ptr->ip, ptr->count);
#endif
            ptr->count++;
            return 0;
        }
        ptr = ptr->next;
    }
#ifdef DEBUG
    printf("Returning 1n");
#endif
    return 1;
}
void *recievethread()
{
    int saddr_size, data_size, sock_raw;
    struct sockaddr_in saddr;
    struct in_addr in;
    unsigned char *buffer = (unsigned char *)malloc(65536);
    sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_UDP);
    if(sock_raw < 0)
    {
        printf("Socket Errorn");
        exit(1);
    }
    while(1) {
        saddr_size = sizeof saddr;
        data_size = recvfrom(sock_raw , buffer , 65536 , 0 , (struct sockaddr *)&saddr , &saddr_size);
        if(data_size < 0) {
            printf("Recvfrom error , failed to get packetsn");
            exit(1);
        }
        struct iphdr *iph = (struct iphdr*)buffer;
        if(iph->protocol == 17)
        {
            unsigned short iphdrlen = iph->ihl*4;
            struct udphdr *udph = (struct udphdr*)(buffer + iphdrlen);
            unsigned char* payload = buffer + iphdrlen + 8;
            if(ntohs(udph->source) == 123) {
                int body_length = data_size - iphdrlen - 8;
                if (body_length > 47) {
                    if(checkInList(inet_ntoa(saddr.sin_addr)) == 1) {
                        insertInList(inet_ntoa(saddr.sin_addr), 0);
                    }
                }
            }
        }
    }
    close(sock_raw);
}
int main()
{
    pthread_t listenthread;
    pthread_create( &listenthread, NULL, &recievethread, NULL);
    // Some tests
    if(checkInList("192.168.2.1") == 1) {
        insertInList("192.168.2.1", 0);
    }
    if(checkInList("8.8.8.8") == 1) {
        insertInList("8.8.8.8", 0);
    }
    while(1) {
        sort();
        printInList();
        sleep(1);
    }
    printf("n");
    return 0;
}

抱歉,如果它没有意义,如果你认为它会帮助我,请随意将我重定向到另一个线程。

正如其他人所指出的,您需要锁定列表以使其正确。

然而,问题的直接原因是inet_ntoa()返回一个指向静态分配缓冲区的指针,该指针在下一次调用时被覆盖。你在链表中记录了一个指向这个缓冲区的指针,所以当你下次调用inet_ntoa()时,链表节点指向的字符串会发生变化。

插入节点时需要复制字符串:

link->ip = strdup(ipaddr);

一个简单的锁定方法是创建一个全局的pthread_mutex_t:
pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;

,然后锁定它的列表检查/插入:

pthread_mutex_lock(&list_lock);
if (checkInList(inet_ntoa(saddr.sin_addr)) == 1) {
    insertInList(inet_ntoa(saddr.sin_addr), 0);
}
pthread_mutex_unlock(&list_lock);

和周围的sort/print:

pthread_mutex_lock(&list_lock);
sort();
printInList();
pthread_mutex_unlock(&list_lock);

相关内容

  • 没有找到相关文章

最新更新