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++

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 5
    Points : 3
    Points
    3
    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 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    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
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 5
    Points : 3
    Points
    3
    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 éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Février 2005
    Messages : 5 073
    Points : 12 119
    Points
    12 119
    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
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 5
    Points : 3
    Points
    3
    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 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    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.

  7. #7
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

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

    En effet après avoir regardé des tuto ailleurs pour les sockets (notamment le votre qui est super) j'ai trouvé du code qui semble beaucoup plus propre et moins approximatif (plus proche d'un système UNIX).
    J'ai donc réécrit le tout. En effet le startup a été déplacé en dehors du constructeur. Un oubli idiot de ma part.

    Le getaddrinfo est inutile dans le cas de mon application car je communique sur la même machine je l'ai donc également retiré mais merci pour ces informations.

    Le problème réside dans le fait que le système empêche deux applications UWP de communiquer entre elles via les socket (donc en localhost). C'est une restriction du système.
    J'ai refait le test avec deux applications Win32 console (l'une serveur et l'autre client) et la connexion se fait sans problèmes.
    Pour l'instant, ou j'en suis dans mes recherches, il semble que ce sois l'application UWP Serveur qui refuse les connexions provenant de la même machine et non le client qui refuse de se connecter.

    Le système interdit cette façon de faire communiquer les applications UWP via socket certainement pour un principe de sécurité.

    L'info est donnée dans la note au début de l'article :

    https://docs.microsoft.com/en-us/win...orking/sockets

  8. #8
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Si tu fais de l'UWP le code est sensiblement le même pour les sockets normaux (non sécurisés), mais tu dois avoir un package manifest et un network manifest où configurer les connexions dans tous les cas. Mais c'est un problème UWP spécifique.
    Désactiver le firewall devrait permettre aux données de transiter.
    Si tu fais une app UWP tu as certainement une personne chez Microsoft qui gère et devrait t'aider, ou au moins accès à certaines documentations non-toujours disponibles publiquement sur internet.

    https://docs.microsoft.com/en-us/win...y-declarations
    > internetClient
    > privateNetworkClientServer
    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.

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Février 2005
    Messages : 5 073
    Points : 12 119
    Points
    12 119
    Par défaut
    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.
    Je suis plus "Francisque dans la tronche" que débat à "fleuret moucheté", on se refait pas.
    On va plus vite à une solution sans passer par des circonvolutions et des compromis bancals.

    Vous n'êtes très certainement plus un enfant, c'est de l'andragogie et non de la pédagogie qu'il vous faut, normalement.
    Il faut donc commencer par déconstruire ce que vous pensez savoir avant de vous expliquer ce qu'il faut "apprendre".
    D'où le coup de hache dans le melon, pour qu'il dégonfle un peu.
    Le même melon ou chevilles qu'il faut faire dégonfler aux jeunes diplômés pour qu'il commence à comprendre que dans la "vrai" vie, c'est pas comme dans les livres et les examens.

    Votre phrase me fait penser à un adapte d'une secte qui a peur "du grand méchant monde". Vos professeurs, ils sont pas un peu gourous manipulateurs, vous obligeant à utiliser des trucs vieux de plus de 30 ans, complètement obsolètes, juste pour maintenir leur emprise sur vous ?

    @tchoalien, personne n'a appris à marcher sans se casser la gueule, et à un moment donné, il faut laisser le youpala de côté.

    On n'ai pas si méchant.

    mais comme je l'ai expliqué il s'agit d'un proto, donc je fais des tests rapidement.
    Un proto est là pour valider des choix, il ne doit pas être fait à la va-vite mais ne faire que peu de chose MAIS IL DOIT LES FAIRE CORRECTEMENT !

    L'article donc vous donnez vous-même l'URL montre qu'il ne faut pas prendre les vieux machins génériques, sous peine de vous prendre toutes les mécaniques de SandBoxing dans la tronche.
    Suivez les recommandations données par l'article :
    https://docs.microsoft.com/fr-fr/win...p-to-app/index

+ 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