[C] Bug dans une application client-serveur très simple

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Je suis en train de développer deux programmes très élémentaires (un client et un serveur) qui peuvent interagir entre eux via le protocole TCP.

Port client : choisis par le système
Port serveur : 1664
Adresse IP serveur : 8.8.8.8

Le problème, c’est que le client n’arrive pas à se connecter au serveur. Il prend un temps très long à se connecter, puis s’éteint en mettant errno à la valeur ETIMEDOUT (The attempt to connect timed out without establishing a connection) (documentation ici).

qsd

Une idée d’où pourrait venir le problème ?

Ce que j’ai déjà essayé :

  • Désactiver tous les pare-feu sur l’ordinateur et les antivirus
  • Mettre le port client manuellement à 1664
  • Changer le port à 1666 côté serveur et client
  • Démarrer le client avant le serveur, et vice-versa

Le code du client (il paraît long mais sa logique est simple) :

#define _DEFAULT_SOURCE
#define SERVEUR_PORT 1664

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>

int main(void)
{
    printf("--- Programme client version 1.0.3 ---\n");

    struct sockaddr_in local_addr, serv_addr;
    int res, sockfd;

    // ------ Initialisation socket file descriptor --------
    sockfd = socket (PF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        fprintf(stderr, "Unable to initialize socket file descriptor.\n");
        return EXIT_FAILURE;
    }

    
    // ---- Initialisation de local_addr ------
    bzero (&local_addr, sizeof (struct sockaddr_in));

    local_addr.sin_port = htons(0);      // Le choix du port est laissé au système
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);


    // Lien
    res = bind (sockfd, (struct sockaddr *) &local_addr, sizeof (struct sockaddr_in));
    if (res == -1)
    {
        fprintf(stderr, "Unable to bind local socket.\n");
        close(sockfd);
        return EXIT_FAILURE;
    }


    // ---- Initialisation de serv_addr ------
    bzero (&serv_addr, sizeof (struct sockaddr_in));

    serv_addr.sin_port = htons(SERVEUR_PORT);
    serv_addr.sin_family = AF_INET;
    res = inet_aton("8.8.8.8", &(serv_addr.sin_addr));

    if (res == 0)
    {
        fprintf(stderr, "Unable to convert server address.\n");
        close(sockfd);
        return EXIT_FAILURE;
    }




    // Tout est prêt pour se connecter au serveur !
    printf("Pré-connexion réussie...\n");



    

    errno = 0;
    res = connect(sockfd, (struct sockaddr *) &serv_addr, sizeof (struct sockaddr_in));
   
    if (res == -1)
    {
        // Ce message s'affichera
        if (errno == ETIMEDOUT)
            printf("The attempt to connect timed out without establishing a connection.\n");
        
        
        fprintf(stderr, "Unable to connect to server.\n");
        close(sockfd);
        return EXIT_FAILURE;
    }


    
    printf("Connexion réussie !\n"); // Ne s'affichera pas hélas
    close (sockfd);

    return EXIT_SUCCESS;
}

Le code du serveur (idem, long mais simple) :

#define _DEFAULT_SOURCE
#define SERVEUR_PORT 1664
#define BACKLOG 20

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>



int main(void)
{
    printf("--- Programme serveur version 1.0.3 ---\n");

    struct sockaddr_in local_addr, cli_addr;
    int res, sockfd, cli_sockfd;
    socklen_t cli_size;

    // --- Initialisation socket file descriptor ---
    sockfd = socket (PF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        fprintf(stderr, "Unable to initialize socket file descriptor.\n");
        return EXIT_FAILURE;
    }


    // ---- Initialisation de local_addr ------
    bzero(&local_addr, sizeof (struct sockaddr_in));

    local_addr.sin_port = htons(SERVEUR_PORT);
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    local_addr.sin_family = AF_INET;



    // ---- Lien ----
    res = bind(sockfd, (struct sockaddr *) &local_addr, sizeof (struct sockaddr_in));
    if (res == -1)
    {
        fprintf(stderr, "Unable to bind local socket.\n");
        close(sockfd);
        return EXIT_FAILURE;
    }




    // Mise en écoute du serveur
    res = listen(sockfd, BACKLOG);
    if (res == -1)
    {
        fprintf (stderr, "Listening failed.\n");
        close (sockfd);
        return EXIT_FAILURE;
    }




    // Cette étape réussit !
    printf("Mise en écoute...\n");





    // Accepte les connexion
    cli_sockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &cli_size);
    if (cli_sockfd == -1)
    {
        fprintf(stderr, "Unable to accept new client.\n");
        close(sockfd);
        return EXIT_FAILURE;
    }



    printf("Accepte les connexions... "); // échoue !
    close (cli_sockfd);
    close (sockfd);

    return EXIT_SUCCESS;
}

Ce que je ne comprends pas, c’est pourquoi le client n’arrive pas à se connecter (ligne 73 du code client qui mets en attente le programme pendant 1 minute).
Désolé pour la longueur du message, j’ai essayé de faire au plus court.

Ton code marche bien.

Tu ne sembles pas avoir les bases en réseau. Tu sais ce qu’est une adresse IP ? Indique 127.0.0.1 à la place de 8.8.8.8 pour l’IP du serveur ça devrait mieux marcher.

8.8.8.8 est l’IP du server DNS primaire publique de Google. C’est une IP utilisé généralement pour faire des tests. Étant un serveur DNS, c’est son port 53 qui est ouvert.

Ici, ton serveur n’utilise pas l’IP de Google mais tourne en local sur ta machine (non ?) donc son IP est 127.0.0.1.

Si tu as besoin de réviser un peu le réseau, il y a un tutoriel intéressant sur le site. Les Réseaux de Zéro.

Désolé pour la longueur du message, j’ai essayé de faire au plus court.

Aucun problème. Généralement trop long n’est pas un problème.

+3 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte