2015-09-30 1 views
0

Je vais d'abord vous donner l'objectif du code. C'est un udpserver et est censé fournir des statistiques sur le nombre de paquets reçus et le temps pris etc. Le code client fait partie du code embarqué de l'entreprise et ne peut pas être partagé. Voici le code.Code de programmation de socket Exécute sous XP mais échoue sur Windows 7

/* 
** 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; 
} 

Maintenant pour l'environnement en cours d'exécution.

J'ai exécuté le code ci-dessus sur Windows XP après l'avoir compilé en utilisant Cygwin pour générer un fichier .exe. Cela fonctionne parfaitement bien là-bas. Cependant quand je compilé sur un ordinateur Windows 7 machine (à nouveau en utilisant Cygwin (fichier setup_X86.exe BTW) il compile très bien mais en l'exécutant débogage montre qu'il n'atteint que le journal de débogage

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

sur la ligne 191.

J'ai essayé exécuter l'exécutable en utilisant la compatibilité XP SP3 et privilèges d'administrateur. J'ai essayé de regarder en ligne mais je trouve pas de solution. Est-ce que quelqu'un sait si je l'ai fait une erreur lors de la compilation? j'ai fait simple

gcc -o udpserver.exe udpserver.c 

et c'était réussi. S'il vous plaît laissez-moi savoir ce que je peux faire pour affiner le problème. Je suis encore relativement nouveau dans la programmation et la programmation de sockets en général.

Merci d'avance!

+0

Le client s'exécute-t-il sur le même ordinateur ou sur le réseau? Si le client est sur le réseau, vous souvenez-vous de configurer le pare-feu? –

+0

Désolé, il m'a fallu un certain temps pour répondre. J'ai été retiré hier pour d'autres travaux. J'ai essayé de désactiver le pare-feu aujourd'hui. Même problème. –

+0

Je vois que vous vous engagez seulement à la première adresse/protocole que vous trouvez; peut-être vous lier à IPv6 lorsque le client attend IPv4, ou peut-être que vous liez à la mauvaise adresse, par exemple, 127.0.0.1 ou l'un des adaptateurs de tunnel? Vous pouvez utiliser 'netstat -a -n -b' pour vérifier la liaison ou ajouter les diagnostics appropriés à votre code. –

Répondre

0

Si vous souhaitez rechercher des adresses à associer, par exemple via getaddrinfo, vous devez généralement vous connecter à toutes les adresses que vous trouvez. Sinon, sur les machines avec plusieurs adaptateurs, votre service ne sera disponible que sur un seul adaptateur choisi au hasard; et même s'il n'y a qu'un seul adaptateur, vous pouvez vous lier au mauvais protocole (comme dans ce cas).

Je crois que l'approche habituelle est de se lier à la place à la « une » adresse, 0.0.0.0 en IPv4, comme décrit dans le documentation for bind:

Si une application ne se soucie pas quelle adresse locale est affectée, spécifiez la valeur constante INADDR_ANY pour une adresse IPv4 locale ou la valeur constante in6addr_any pour une adresse IPv6 locale dans le membre sa_data du paramètre name.