c - 线程中的链表?

标签 c linked-list pthreads

我编写了一个 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)  ]

这意味着我们从 255.255.255.255 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:%d\t", 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:%d\t", 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->%d\n", ptr->ip, ptr->count);
#endif
            ptr->count++;
            return 0;
        }
        ptr = ptr->next;
    }
#ifdef DEBUG
    printf("Returning 1\n");
#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 Error\n");
        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 packets\n");
            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);

围绕排序/打印:

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

关于c - 线程中的链表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39815094/

相关文章:

c 代码输出意外/预期的行为

c# - 创建一个非常简单的单循环列表 C#

c - pthread_cond_t 条件下的 volatile 变量

c - select() 未检测到传入数据

比较 pthread_t 和 int 输入的相等性?

c - 在 Linux 上以编程方式获取有关 ROM 内存类型和大小的信息

c - 为什么在枚举中#define 值?

java - BJP5练习16.7 : deleteBack — Help me understand the solution

c - Linux内核例程的时序测量

java - 为什么在插入 LinkedList 和 ArrayList 时得到关于时间的不同输出