IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Socket client bloquée dans l'état SYN_SENT


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 5
    Par défaut Socket client bloquée dans l'état SYN_SENT
    Bonjour,

    Je viens vous faire part d'un problème de socket.
    C'est la première fois que j'utilise des sockets sous windows. J'ai donc un serveur (Projet WPF C++ sous visual studio 2017 Community) qui est en écoute sur le port 5555. Il est bien en écoute car lorsque je test une connexion depuis ma machine virtuelle Debian à l'aide de la commande :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    echo "Bonjour" | nc 172.16.0.102 5555
    Mon serveur reçoit bien la connexion et lit le message.

    Le problème vient de mon application client. Cette dernière est développée en C++ sous Visual Studio 2017 Community. Lorsque le client est en phase de connexion et que j'observe les port TCP sur ma machine à l'aide de la commande suivante :

    J'obtiens le résultat suivant pour mon application client :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     TCP    172.16.0.102:51733     172.16.0.102:5555      SYN_SENT        10920
    Après une recherche, j'apprends que lorsque la connexion est à l'état "SYN_SENT" (trop longtemps) c'est que cette dernière est bloquée par éventuellement le pare-feu. J'ai donc désactivé mon pare-feu mais j'ai toujours cet état. J'ai également tenté de faire la connexion sur l'adresse locale "127.0.0.1" mais j'ai le même résultat.

    Voici le code du serveur qui initialise la socket serveur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
     
    Server::Server(int port)
    {
     
     
    	//Indique qu'on utilise des sockets
    	WSAStartup(MAKEWORD(2, 2), &_WSAData);
     
    	ZeroMemory(&hints, sizeof(hints));
    	hints.ai_family = AF_INET;
    	hints.ai_socktype = SOCK_STREAM;
    	hints.ai_protocol = 0;
    	hints.ai_flags = AI_PASSIVE;
     
    	// Resolve the local address and port to be used by the server
    	int gaiRes = getaddrinfo(NULL, "5555", &hints, &result);
    	if (gaiRes != 0) 
    	{
    		WSACleanup();
    	}
     
    	//Creation de la socket
    	_socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
     
    	if (_socket == INVALID_SOCKET) 
    	{
    		freeaddrinfo(result);
    		WSACleanup();
    	}
     
     
    	// Setup the TCP listening socket
    	int bindResult = bind(_socket, result->ai_addr, (int)result->ai_addrlen);
    	if (bindResult == SOCKET_ERROR) 
    	{
    		freeaddrinfo(result);
    		closesocket(_socket);
    		WSACleanup();
    	}
     
    	freeaddrinfo(result);
     
    	if (listen(_socket, SOMAXCONN) == SOCKET_ERROR) 
    	{
    		closesocket(_socket);
    		WSACleanup();
    	}
     
    }
     
    SOCKET Server::Accept()
    {
    	SOCKADDR_IN client_sin;
    	int cs_size = sizeof(client_sin);
     
    	SOCKET client;
    	if ((client = accept(_socket, NULL, NULL)) != INVALID_SOCKET)
    	{
    		return client;
    	}
    	else {
    		return -1;
    	}
    }

    Et voici le code de la socket client :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
     
    NetworkClient::NetworkClient(const char * address, const char * port)
    {
    	int WSAResult = WSAStartup(MAKEWORD(2, 2), &WSAData);
    	if (WSAResult != 0)
    	{
    		printf("WSAStartup failed : %i\n", WSAResult);
    	}
     
    	Sresult = NULL;
    	ptr = NULL;
     
    	ZeroMemory(&hints, sizeof(hints));
    	hints.ai_family = AF_INET;
    	hints.ai_socktype = SOCK_STREAM;
    	hints.ai_protocol = 0;
     
     
    	int getAddrInfoResult = getaddrinfo(address, port, &hints, &Sresult);
    	if (getAddrInfoResult != 0)
    	{
    		printf("getaddrinfo failed : %i\n", getAddrInfoResult);
    		WSACleanup();
    	}
     
    	ConnectSocket = INVALID_SOCKET;
     
    	ptr = Sresult;
     
    	ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
     
    	if (ConnectSocket == INVALID_SOCKET)
    	{
    		printf("Error at socket(): %ld\n", WSAGetLastError());
    		freeaddrinfo(Sresult);
    		WSACleanup();
    		//return 1;
    	}
     
     
    }
     
    void NetworkClient::Connect()
    {
    	//Connect to server
    	int connectResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
    	if (connectResult == SOCKET_ERROR)
    	{
    		printf("Connect failed : %i\n", connectResult);
    		closesocket(ConnectSocket);
    		ConnectSocket = INVALID_SOCKET;
    	}
     
    	freeaddrinfo(Sresult);
     
    	if (ConnectSocket == INVALID_SOCKET) 
    	{
    		printf("Unable to connect to server!\n");
    		WSACleanup();
    	}
     
     
    }
    Les paramètres passés au constructeur sont "127.0.0.1" et "5555".
    Le client bloque dans la méthode Connect() lors de l'appel de la fonction connect().

    J'ai l'impression que Windows bloque la connexion sur ma boucle locale.
    Si vous avez une idée pour résoudre ce problème je suis preneur.

    Merci d'avance.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 151
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 151
    Billets dans le blog
    4
    Par défaut
    Le port est sensé être un unsigned short. Et il faut le convertir en valeur valide sur le réseau.
    connect est bloquant tant que la connection n'a pas été réalisée. Vu le port, et le code en général très approximatif et difficilement lisible, tous ces getaddrinfo inutiles et j'en passe, variables membres non avenues et dont on ne connait rien dans ce snapshot (trop) succint, je doute qu'il y parvienne jamais (et vu qu'il est bloqué dedans, j'ai surement raison).
    Une connection à un serveur, c'est sensé être simple : http://bousk.developpez.com/cours/re...ers-pas/#LVI-A
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 5
    Par défaut
    Merci pour votre réponse.


    Le code est brouillon je l'accorde (C'est en phase de prototype) par contre la procédure de connexion au serveur est celle conseillée sur MSDN :

    https://msdn.microsoft.com/fr-fr/lib...(v=vs.85).aspx

    Pour le port il doit être passé en PCSTR (const char *) à la fonction "getaddrinfo" (qui apparait qu'une seule fois dans le code client...).

    J'ai également essayé de reset winsock avec la commande :

    Mais le problème n'est pas résolu.


    EDIT :

    J'ai changé l'approche pour la connexion au serveur en suivant le lien que vous avez fourni

    voici desormais le code client :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    NetworkClient::NetworkClient(const char * address, int port)
    {
    	//Informe qu'on utilise les fonction de la dll
    	int WSAResult = WSAStartup(MAKEWORD(2, 2), &WSAData);
    	if (WSAResult != 0)
    	{
    		printf("WSAStartup failed : %i\n", WSAResult);
    	}
     
    	//Creation de la socket client TCP
    	_Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     
    	//Ajout des informations sur le serveur
    	_Server.sin_addr.s_addr = inet_addr(address);
    	_Server.sin_family = AF_INET;
    	_Server.sin_port = htons(port);
     
    }
     
    void NetworkClient::Connect()
    {
    	//Connexion au serveur
    	if (connect(_Socket, (sockaddr*)&_Server, sizeof(_Server)) == SOCKET_ERROR)
    	{
    		printf("Echec lors de la connexion. \n");
    		closesocket(_Socket);
    		_Socket = INVALID_SOCKET;
    	}
     
     
    }

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 502
    Par défaut
    Au risque de passer pour le 2ème vieux con du Muppets-show, je suis d'accord avec @Bousk.
    C'est tellement à des années-lumière de comment il faut faire la chose, que le fait qu'il y est des trucs qui marchouille tient plus de hasard brownien que de l'horlogerie suisse.
    En plus, quand on voit ce qu'offre .NET en terme de primitives réseaux et voir du code WPF faire du "Trumpet Winsock" du début des années 90, c'est comme voire une navette spéciale lancée avec un lance-pierre.

    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    Cela n'a donc rien à faire dans un constructeur de socket !!!! Il y a potentiellement plusieurs sockets et le constructeur et destructeur ne sont pas en début et en fin de process !!!

    Pourquoi utiliser "getaddrinfo" quand vous disposez déjà de toutes les informations nécessaires ?

    En plus, la gestion des données retournées par "getaddrinfo", c'est vraiment n'importe quoi, à base de variables statique (si l'on en croit une notation à la hongroise complètement WTF).

    >Pour le port il doit être passé en PCSTR (const char *) à la fonction "getaddrinfo" (qui apparait qu'une seule fois dans le code client...).
    Ouais, mais avant de mettre tout et n'importe quoi, du moment que ça respecte plus ou moins la signature, faut quand même lire la documentation :
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    Je vous signale que utilisez des API système C datant de plus de 25 ans, on peut leur foutre n'importe quoi dans la gueule, elles vous renvoient n'importe quoi.

    "Sresult" et "ptr" qui représente la même chose sous forme de pointeur, champ de la "socket" ou statique, GG pour le nombre d'emmerde potentiel pour du code qui sert A RIEN.

    Bon, ce code est tellement à l'ouest qu'on va pas chercher à le débuguer.
    - Utilisez un débogueur pour vérifier la tête des paramètres que vous enfournez dans la gueule des primitives réseaux.
    - Utilisez un Sniffer réseau comme WireShark pour voir quel machin vous essayez de cibler dans le cyberspace.

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 5
    Par défaut
    Le code fonctionne. Il s'agissait d'un problème de network (loopback) isolation.

    Pour le coup il n'y a qu'une socket présente dans l'application client. Dans l'app du serveur il y en aura plusieurs mais comme je l'ai expliqué il s'agit d'un proto, donc je fais des tests rapidement. La mise au propre est l'étape d'après.

    Je sais pas c'est quoi votre problème Bacelar mais vous représentez bien cette communauté critiquée par bon nombre des mes professeurs. Frustration personnelle ? Peut être. En tous cas vous ne donnez pas envie de dialoguer avec la communauté des développeurs présent sur le net. Et puis prenez peut être le temps de lire l'EDIT qui a été faite dans mon deuxième message.

    Cordialement.

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 151
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 151
    Billets dans le blog
    4
    Par défaut
    L'utilisation de getaddrinfo peut éventuellement avoir un intérêt si tu ne sais pas si ton adresse est IPv4 ou IPv6. Ca reste léger et rare comme utilisation. Et il faut gérer correctement les résultats retournés dans tous les cas.
    Le startup ne doit être fait qu'une seule fois, il vaut mieux l'avoir en dehors du constructeur si tu espères avoir plus qu'un socket chez le client. En bonne pratique le release ne doit pas être oublié non plus.
    Microsoft m'a habitué à de la documentation approximative, mais celle-là est particulièrement mauvaise. C'est tout au plus une suite de tuto qui présente un aspect, pas vraiment une documentation de bonnes pratiques et utilisables pour une appli complète. Y'a aucune architecture et recopier ça tel quel mène juste à du mauvais code. Surtout avec une API C.
    Je prêche pour ma paroisse mais je recommande la lecture de mon cours (en cours d'écriture) qui représente une façon portable et claire d'avoir un moteur réseau, facile à (re)lire en cas de problème. Enfin, ce code a été éprouvé à de nombreuses reprises et des samples disponibles tant client que serveur si tu veux uniquement les utiliser pour tester ton propre serveur ou client.
    Ca facilitera aussi la recherche d'erreurs, en particulier les appels à l'aide. Plutôt que des lignes cryptiques made in MSDN.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème dans les sockets Client Serveur Java
    Par rabah15 dans le forum Entrée/Sortie
    Réponses: 1
    Dernier message: 30/09/2014, 16h03
  2. [WD12] Client mail par défaut dans les états
    Par jcpas dans le forum WinDev
    Réponses: 3
    Dernier message: 01/04/2010, 10h07
  3. Base bloquée dans l'état "en cours d'arrêt"
    Par puck78 dans le forum Administration
    Réponses: 3
    Dernier message: 11/06/2009, 18h21
  4. Réponses: 20
    Dernier message: 10/07/2006, 16h53
  5. Réponses: 2
    Dernier message: 12/10/2004, 13h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo