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