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

MFC Discussion :

[MFC] CSocket ... problème à la fermeture


Sujet :

MFC

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Août 2002
    Messages
    225
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 225
    Points : 118
    Points
    118
    Par défaut [MFC] CSocket ... problème à la fermeture
    Salut !

    Depuis (très) peu de temps je me suis mis à la programmation réseaux. Je sais qu'il existe un forum spécifique pour le développement réseaux mais d'un autre côté comme je développe sous Visual C++ 6.0 je me suis dit que je devrais peut être poster ma question sur ce forum plutôt que sur l'autre.

    Bref, pour me faire la main je développe un serveur echo au sein d'une application de type boîte de dialogue (avec le support socket). J'ai trois classes : CApp, CDlg et CEchoServer.

    Ma classe CDlg possède deux CButton (Stop et Start serveur) et une CListBox.

    Le fonctionnement désiré est le suivant. L'appui sur START démarre le serveur (si ce n'est pas déjà fait), lequel se met en attente perpétuellement d'une connexion et renvoi le message reçu précédé de <ECHO>. L'appui sur STOP doit arrêter le server.

    Le bouton START démarre donc mon serveur ... ou plutôt devrais je dire créé un thread
    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
     
    void CEchoServer::Start(int nListeningPort)
    {
        if( this->m_pThread == NULL )
        {
            CString szMessage;
     
            this->m_nListeningPortNumber = nListeningPort;
            this->m_bServerMustStop = FALSE;
     
            this->m_pThread = AfxBeginThread(DoListen, this);
            if( this->m_pThread == NULL )
            {
                szMessage.Format( "Could not create the server thread" );
                AfxMessageBox(szMessage, MB_OK, NULL);
            }
        }
    }
    Le code exécuté dans le thread est le suivant :
    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
     
    UINT CEchoServer::DoListen(LPVOID pvParam)
    {
        CEchoServer* pThis = (CEchoServer*)pvParam;
     
        while( pThis->m_bServerMustStop == FALSE )
        {
            CString szMessage;
            CString szStringToReceive;
            CString szStringToSend;
            CSocket sockServer;
            CSocket sockClient;
     
            sockServer.Create(pThis->m_nListeningPortNumber);
            sockServer.Listen();
            sockServer.Accept(sockClient);
            if( pThis->m_bServerMustStop != TRUE )
            {
                CSocketFile sockFile(&pThis->m_sockClient);
                CArchive archIn(&sockFile, CArchive::load);
                CArchive archOut(&sockFile, CArchive::store);
     
                archIn.ReadString(szStringToReceive);
                if( szStringToReceive.Compare( "STOP SERVER" ) == 0 )
                    pThis->m_bServerMustStop = TRUE;
     
                szStringToSend.Format( "ECHO <%s>", szStringToReceive);
                archOut.WriteString(szStringToSend);
                archOut.Flush();
            }
        }
     
        pThis->m_pThread = NULL;
        return 0;
    }
    ...

    J'en arrive (enfin me direz vous) à mon problème : comment arrêter le serveur ( que dois je faire dans la fonction void CEchoServer::Stop() ) ?

    Cas de figure numéro 1 :
    Si aucun client n'est connecté, il me semble que le programme sera bloqué à l'appel de la fonction suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
            sockServer.Accept(sockClient);
    Dans ce cas comment débloquer la situation depuis la fonction void CEchoServer::Stop() ?

    Cas de figure numéro 2 :
    Si un client est connecté, il me semble que le programme sera bloqué à l'appel de la fonction suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
                archIn.ReadString(szStringToReceive);
    Idem, comment débloquer la situation depuis la fonction void CEchoServer::Stop() ?

    Désolé pour "la tartine", j'espère que vous pourrez m'aider. D'avance merci[/code]

  2. #2
    Rédacteur
    Avatar de farscape
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    9 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 9 055
    Points : 17 323
    Points
    17 323
    Par défaut
    salut,
    Pour la socket principal pour la connexion des clients il est plus judicieux de procéder comme suit :
    Faire une classe dérivée de CSocket par exemple CListeningSocket et de surcharger la méthode virtuelle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     virtual void OnAccept(int nErrorCode);
    Le traitement d’acception de la socket client se fera alors dans cette fonction.

    Pour l’init de la socket serveur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    m_pSocket = new CListeningSocket(this); // passage d’un objet pour lien vers l’extérieur classe document view autre chose.
    if (m_pSocket->Create(m_Port)) m_pSocket->Listen();
    Voila ça évite un boucle d’attente de connexion des clients, la socket recevant la demande directement et appelle la fonction OnAccept..


  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Août 2002
    Messages
    225
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 225
    Points : 118
    Points
    118
    Par défaut
    Ok, si j'ai bien tout compris je dois développer une classe spécialisée qui dérive de CSocket et implémanter le traitement des connexions clientes dans la fonction virtuelle OnAccept(). Ma classe de dialogue doit posséder un membre du type de la classe précédente et lorsque j'appui sur mon bouton START j'exécute le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    m_pSocket = new CListeningSocket(this); // passage d’un objet pour lien vers l’extérieur classe document view autre chose. 
    if (m_pSocket->Create(m_Port)) m_pSocket->Listen();
    Ok ok, j'ai encore pleins de questions mais je vais tester cette solution dans un premier temps, je mettrais la balise RESOLU dans la foulée si tout est OK.

    Merci[/code]

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Août 2002
    Messages
    225
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 225
    Points : 118
    Points
    118
    Par défaut
    Ok, c'est cool, ça fonctionne proprement.

    Par contre comme prévu j'ai quelques questions concernant l'arrêt du serveur dans le cas suivant :
    (1) Le serveur est démarré et un client est connecté.
    "Comment faire pour arrêter le serveur dans ce cas ?"

  5. #5
    Rédacteur
    Avatar de farscape
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    9 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 9 055
    Points : 17 323
    Points
    17 323
    Par défaut
    arreté le serveur n'est pas un probleme ,tu fermes la socket cliente tu la detruis .
    tu peux faire un ShutDown(2) puis un Close() .
    et tu laisses la fermeture se faire.
    a toi de gerer la deconnexion coté client.
    avec la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    virtual void OnClose( int nErrorCode );

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Août 2002
    Messages
    225
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 225
    Points : 118
    Points
    118
    Par défaut
    ok mais le problème c'est que lorsque le server est démarré et qu'un client est connecté, l'appel de la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    	archIn.ReadString(szStringToReceive);
    archIn est un objet d'une classe CArchive attaché à un objet CFile.

    Du coup lorsque le server est démarré et qu'un client est connecté, mon IHM est bloquée et le code associé au bouton STOP n'est pas exécuté.

    Le code est le suivant :
    Côté 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
     
    void CMyEchoServer::OnAccept(int nErrorCode) 
    {
    	// TODO: Add your specialized code here and/or call the base class
    	CSocket clientSocket;
    	CString szMessage;
    	CString szStringToReceive; 
                    CString szStringToSend;
     
    	this->Accept(clientSocket);
     
     
    	CSocketFile sockFile(&clientSocket); 
                    CArchive archIn(&sockFile, CArchive::load); 
                    CArchive archOut(&sockFile, CArchive::store); 
     
     
    	archIn.ReadString(szStringToReceive); 
     
     
                    szStringToSend.Format( "ECHO <%s>", szStringToReceive); 
                    archOut.WriteString(szStringToSend); 
                    archOut.Flush(); 
     
    	CSocket::OnAccept(nErrorCode);
    }
    et côté classe de dialogue
    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
     
    void CEchoServerDlg::OnButtonStart() 
    {
    	// TODO: Add your control notification handler code here
    	if( this->m_pServer == NULL )
    	{
    		this->m_pServer = new CMyEchoServer(this);
    		if( this->m_pServer->Create(9000) )
    			this->m_pServer->Listen();
    	}
    }
     
    void CEchoServerDlg::OnButtonStop() 
    {
    	// TODO: Add your control notification handler code here
    	if( this->m_pServer )
    	{
    		this->m_pServer->Close();
    		delete this->m_pServer;
    		this->m_pServer = NULL;
    	}
    }
    Si je veux encapsuler le traitement dans un thread je ne vois pas trop où le faire pour éviter de bloquer mon IHM. Peux tu m'aider sur ce point ?

  7. #7
    Rédacteur
    Avatar de farscape
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    9 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 9 055
    Points : 17 323
    Points
    17 323
    Par défaut
    pour onAccpet ok pour la creation socket client a un detail :ne gere pas l'emission reception dedans ...
    ça doit etre externe ..

    ce qui veut dire socket client non local à la fonction ainsi que le socketfile.
    (d'ou ma remarque de passer en argument un pointeur sur un classe dans la construction de la socket d'ecoute ).

    pour cela même combat la reception ne doit pas etre traitée de cette maniere:
    tu fais une classe derivée pour la socket cliente et tu redefinis la fonction virtuelle OnReceive ,et dans cette fonction tu procedes a la reception.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Août 2002
    Messages
    225
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 225
    Points : 118
    Points
    118
    Par défaut
    C'est cool ca tout fonctionne impécablement, merci

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 03/05/2005, 09h12
  2. [TQuery] problème de fermeture
    Par mammistegon dans le forum Bases de données
    Réponses: 5
    Dernier message: 29/01/2005, 18h15
  3. [Thread][socket]Problème de fermeture d'un thread
    Par meda dans le forum Concurrence et multi-thread
    Réponses: 4
    Dernier message: 04/11/2004, 01h03
  4. Problème de fermeture de l'application
    Par SkyDev dans le forum Langage
    Réponses: 2
    Dernier message: 16/06/2004, 02h06
  5. Problème de fermeture de balise <tr>
    Par nuage dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 18/03/2004, 09h55

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