简体   繁体   中英

Socket programming code Executes on XP but fails on Windows 7

First let me give you the objective of the code. It is a udpserver and is supposed to provide statistics on the number of packets received and time taken etc etc. The client code is part of the company's embedded code and cannot be shared. Below is the code.

/*
** listener.c -- a datagram sockets "server" demo
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <netdb.h>
#include <time.h>
#include <math.h>
#include "windows.h"

#define MYPORT "4950"   // Default port number users will be connecting to

#define MAXBUFLEN 1497 

#define TIMEOUT_PERIOD_IN_SEC  5  /* Time out after the last packet reception */

//#define DEBUG_ENABLE

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}


int main(int argc, char *argv[]) 
{
    int sockfd;
    struct addrinfo hints, *servinfo, *p;
    int rv;
    int numbytes=0;
    struct sockaddr_storage their_addr;
    char buf[MAXBUFLEN];
    socklen_t addr_len;
    char s[INET6_ADDRSTRLEN];
    int flag=1;
    struct timeval tv;
    fd_set rfds;
    int retval;
    long long  length = 0;
    double   totalTxBits=0;
    double   dataRate=0;

        FILETIME   sysTime;
        long long  startTime=0;
        long long  endTime=0;
        long long  timeDurationInMicSec;
    long total_no_of_packets=0;
    long expected_length=0;
        char portNum[8];
        int i;

       switch(argc)
       {
       case 2:
               {
                   strncpy(portNum, argv[1],8);

                   if((0==strcmp(portNum,"-h")) || (0==strcmp(portNum,"h")))
                   {
                       printf("\r\nUsage: \r\n\t udpserver.exe [<port num>] [<expected length(bytes)>]\r\n");
                       printf("\r\nNote: All parameters are optional\r\n");
                       printf("\r\nExample: \r\n\t i) udpserver.exe \r\n");
                       printf("\n\t ii) udpserver.exe 8000 \r\n");
                       printf("\n\t iii) udpserver.exe 8000 100000\r\n");
                       printf("\n\t iv) udpserver.exe 8000 100000 1400\r\n");

                       return 1;
                   }

                   // Make sure that argument contains nothing but digits
                   for (i = 0; i < strlen(portNum); i++)
                   {
                       if (!isdigit(portNum[i]))
                       {
                           printf("\r\n Invalid port number \r\n");
                           printf("\r\nUsage: \r\n\t udpserver.exe [<port num>] [<expected length>]\r\n");
                            return 1;
                       }
                   }

               }
           break;

       case 3:
            {
               strncpy(portNum, argv[1],8);

               /* Make sure that argument contains nothing but digits */
               for (i = 0; i < strlen(portNum); i++)
               {
                   if (!isdigit(portNum[i]))
                   {
                       printf("\r\n Invalid port number \r\n");
                       return 1;
                   }
               }

               printf("\r\nExpected length                 :%d \r\n",atoi(argv[2]));
               expected_length = atoi(argv[2]);
            }
        break;

           case 4:
            {
               strncpy(portNum, argv[1],8);

                /* Make sure that argument contains nothing but digits */
               for (i = 0; i < strlen(portNum); i++)
               {
                   if (!isdigit(portNum[i]))
                   {
                       printf("\r\n Invalid port number \r\n");
                       return 1;
                   }
               }


               expected_length = atoi(argv[2]);
               expected_length  = expected_length * atoi(argv[3]);
               printf("\r\nExpected length                 :%d (%d x %d)\r\n",expected_length,atoi(argv[2]),atoi(argv[3]));
           }
       break;

       default:
       {   
           strcpy(portNum, MYPORT);
               expected_length=0;
       }
       break;
       }

       printf("\r\nWaiting on port number          :%s \r\n",portNum);

       tv.tv_sec = TIMEOUT_PERIOD_IN_SEC; /* Time out after the last packet reception */
       tv.tv_usec = 0;

       memset(&hints, 0, sizeof hints);
       hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
       hints.ai_socktype = SOCK_DGRAM;
       hints.ai_flags = AI_PASSIVE; // use my IP

       if ((rv = getaddrinfo(NULL, portNum, &hints, &servinfo)) != 0) {
           fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
       return 1;
       }

    // loop through all the results and bind to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("listener: socket");
            continue;
        }

        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("listener: bind");
            continue;
        }

        break;
    }

    if (p == NULL) {
        fprintf(stderr, "listener: failed to bind socket\n");
        return 2;
    }

    freeaddrinfo(servinfo);

    total_no_of_packets=0;

    while(flag)
    {

#ifdef DEBUG_ENABLE
        printf("listener: waiting to recvfrom...\n");
#endif /* DEBUG_ENABLE */

        addr_len = sizeof their_addr;

        if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0,
            (struct sockaddr *)&their_addr, &addr_len)) == -1)
        {
            perror("recvfrom");
            exit(1);
        }

        total_no_of_packets++;

#ifdef DEBUG_ENABLE
        printf("listener: got packet from %s\n",
        inet_ntop(their_addr.ss_family,
        get_in_addr((struct sockaddr *)&their_addr),
        s, sizeof s));
#endif /* DEBUG_ENABLE */

        if (0==length)
        {
            GetSystemTimeAsFileTime(&sysTime);
            startTime = sysTime.dwHighDateTime;
            startTime =  (startTime<<32) | sysTime.dwLowDateTime; /* number of 100-nanosecond intervals  */

        }

#ifdef DEBUG_ENABLE
        printf("listener: packet is %d bytes long\n", numbytes);
#endif /* DEBUG_ENABLE */
        length+=numbytes;

        #if 0
        GetSystemTimeAsFileTime(&sysTime);
        endTime =sysTime.dwHighDateTime;
        endTime =  (endTime<<32) | sysTime.dwLowDateTime; /* number of 100-nanosecond intervals  */
        #endif

        buf[numbytes] = '\0';

#ifdef DEBUG_ENABLE     
        printf("listener: packet contains \"%s\"\n", buf);
#endif /* DEBUG_ENABLE */

        FD_ZERO(&rfds);
        FD_SET(sockfd, &rfds);
        retval = select(sockfd+1, &rfds, NULL, NULL, &tv);

        if (retval == 0)
        {   
            GetSystemTimeAsFileTime(&sysTime);
                    endTime =sysTime.dwHighDateTime;
            endTime =  (endTime<<32) | sysTime.dwLowDateTime; /* number of 100-nanosecond intervals  */
                    timeDurationInMicSec  =(endTime - startTime) / (long long)10;

                     /* Subtract the last time-out value  */
                   if(timeDurationInMicSec)
                   {
                       timeDurationInMicSec -= ((long long)(TIMEOUT_PERIOD_IN_SEC *1000*1000));
                   }

                   printf("\r\n$Time taken                     :%ld micro sec\r\n",timeDurationInMicSec);

                   /* Convert to bits */
                   totalTxBits = length*8;

                   if(timeDurationInMicSec)
                   {
                       dataRate = (totalTxBits*1000*1000)/timeDurationInMicSec;
                   }

                   if(dataRate)
                   {
                       printf("$Number of packets recieved     :%lld\r\n",(total_no_of_packets));
                       printf("$Total number of bytes recieved :%lld\r\n",(length));

                       printf("\r\n$DataRate                       :%f bits per sec\n",dataRate);
                       printf("\r\n$DataRate                       :%f kbps (kilo bits per sec)\n",(dataRate/1024));

                       printf("\r\nNet throughput                  :%f mbps (mega bits per sec)\n",(dataRate/(1024*1024)));

                       if(0 != expected_length)
                       {
                           if(expected_length >= length)
                           {
                               printf("\r\nData loss                       :%lld bytes ( %f percentage)",(expected_length - length), ((float)((expected_length - length)*100))/(float)expected_length);
                           }
                       }

                   }
                   else
                   {
                       printf("$Error: Unable to calculate throughput.");
                   }

            break;
        }

    }

    close(sockfd);
    return 0;
}

Now for the running environment.

I ran the above code on Windows XP after compiling it using Cygwin to generate a .exe file. It works perfectly well there. However when I compiled it on a windows 7 machine (again using cygwin (setup_X86.exe file btw) it compiles perfectly well but while executing it debug shows that it only reaches the debug log

"printf("listener: waiting to recvfrom...\n");

on line 191.

I tried running the executable using XP SP3 compatibility and Administrator Privileges. I've tried to look online but I found no solution. Does anyone know if I've made a mistake during compilation? I did a simple

gcc -o udpserver.exe udpserver.c

and it was successful. Please let me know what I can do to further narrow down the problem. I'm still fairly new to socket programming and programming in genenral.

Thanks in advance!

If you're going to search for addresses to bind to, eg, via getaddrinfo, you typically need to bind to all the addresses you find. Otherwise, on machines with multiple adapters, your service will only be available on a single adapter chosen at random; and even if there is only a single adapter, you may bind to the wrong protocol (as in this case).

I believe the usual approach is to instead bind to the "any" address, 0.0.0.0 in IPv4, as described in the documentation for bind :

If an application does not care what local address is assigned, specify the constant value INADDR_ANY for an IPv4 local address or the constant value in6addr_any for an IPv6 local address in the sa_data member of the name parameter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM