2010-07-30 6 views
2

Sur la base des réponses que j'ai reçu de this thread, j'ai créé ceci:programmation Socket en C, en utilisant la fonction select()

//Server 

    sock_init(); //from SFL, see http://legacy.imatix.com/html/sfl/ 

    timeout = 50000; 

    serv_sock_input[0] = TCP(1234); 
    serv_sock_input[1] = UDP(9876); 

    input_protocols[0] = "tcp"; 
    input_protocols[1] = "udp"; 

    while (1) 
    { 
     FD_ZERO(&sock_set); 
     for (x = 0; x<number_of_inputs; x++) 
     { 
      FD_SET(serv_sock_input[x], &sock_set); 
     } 

     select_timeout.tv_sec = timeout; 
     select_timeout.tv_usec = 0; 

     if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0) 
      printf("No requests"); 
     else 
     { 
      for (x = 0; x<number_of_inputs; x++) 
      { 
       if (FD_ISSET(serv_sock_input[x],&sock_set)) 
       { 
        printf("\nRequest on port %d: \n", x); 
        if ((strcmp(input_protocols[x],"tcp")) == 0) //in this case, 0 returned == TRUE 
        { 
         accept_socket(serv_sock_input[x]); 
         printf("Input TCP Port %d\n",x); 
         close_socket(serv_sock_input[x]); 
        } 
        else 
        { 
         printf("Input UDP Port %d\n",x); 
        } 
       } 
      } 
     } 
    } 
    sock_term(); 
} 

int TCP (unsigned short port) 
{ 
    int sock;       
    struct sockaddr_in servAddr; 

    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 
     exit(1); 

    memset(&servAddr, 0, sizeof(servAddr)); 
    servAddr.sin_family = AF_INET;   
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    servAddr.sin_port = htons(port);    

    if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) 
     exit(1); 

    if (listen(sock, 5) < 0) 
     exit(1); 

    return sock; 
} 

int UDP (unsigned short port) 
{ 
    int sock;      /* socket to create */ 
    struct sockaddr_in servAddr; /* Local address */ 

    /* Create socket for sending/receiving datagrams */ 
    if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 
     exit(1); 

    /* Construct local address structure */ 
    memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */ 
    servAddr.sin_family = AF_INET;    /* Internet address family */ 
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ 
    servAddr.sin_port = htons(port);  /* Local port */ 

    /* Bind to the local address */ 
    if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) 
     exit(1); 


    return sock; 
} 

//Client 
sock_init(); 

    if ((client_sock_output = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 
     exit(1); 

    memset(&client_addr, 0, sizeof(client_addr)); 
    client_addr.sin_family  = AF_INET; 
    client_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    client_addr.sin_port  = htons(1234); 

    if (connect(client_sock_output, (struct sockaddr *) &client_addr, sizeof(client_addr)) < 0) 
     exit(1); 

    closesocket(client_sock_output); 

    sock_term(); 

Wh Si le serveur démarre, le serveur est bloqué sur l'instruction if(select(...)). Par conséquent, lorsque j'exécute le serveur, puis le client, le client se connecte au serveur (parfois, il faut plusieurs fois pour exécuter le client avant de se connecter). Ensuite, l'instruction if(select...)) n'est plus vraie et passe à l'autre.

Ensuite, le client ferme la connexion et le programme. Cependant, et c'est où mon problème se produit, l'instruction if(select(...)) est toujours false. Je reçois cette sortie:

Request on port 0: 
Input TCP Port 0 

Request on port 1: 
Input UDP Port 1 

Cette sortie se répète pour toujours. Comment se fait-il qu'il ne reste pas coincé au if(select(...))?

Répondre

5

Vous avez deux problèmes: vous ne comprenez pas comment accept() fonctionne dans TCP et vous devez lire les données entrantes dans UDP. Select() vous indique qu'un socket d'écoute a une connexion à accepter, ou que le socket de lecture a des données à lire.

Pour choisir d'arrêter de vous le dire, vous devez réellement lire les données ou accepter la connexion.

Dans votre branche UDP, vous devez appeler receiv pour obtenir les données. Si vous ne le faites pas, sélectionnez continuera à vous dire que vous avez des données.

Dans votre branche TCP, vous appelez accept_socket. Je ne sais pas quelle est votre implémentation, mais il est probablement faux de fermer le socket que vous venez d'appeler accept(). accept() renvoie une nouvelle socket pour vous - celle que vous devriez utiliser pour IO. Si quelque chose doit être fermé, c'est ce nouveau socket.

1

Veuillez vérifier pourquoi vous avez ceci dans le serveur.

if (select (0, & sock_set, NULL, NULL, & select_timeout) == 0)

remplacer par

if (select (maxDescPlus1, & sock_set, NULL, NULL, & select_timeout) == 0)

où maxDescPlus1 -> est le nombre de descripteurs à sel ect plus 1 valeur.

Questions connexes