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] Thread et CSocket::accept


Sujet :

MFC

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 49
    Par défaut [MFC] Thread et CSocket::accept
    Bonjour à tous,

    Je me suis lancé dans un projet de programmation réseau avec MFC. En ce moment j'ai un problème avec la méthode CSocket::accept. Pour mon application serveur(CServeur) qui est un CDocument avec deux threads: un qui attend l'ajout de connection et les ajoutes à une liste de client, un autre qui parcours la liste des clients pour voir s'il n'y a pas des données à être lu et les diffuse sur les autre clients

    Le problème se situe dans un assert du fichier sockcore.cpp, c'est la méthode accept. Mon code 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
     
    UINT runAddConnection(LPVOID pParam) {
      CServeur *serveur = (CServeur *)pParam;
      while (serveur->isStarted()) {
         CSocket client;
         if (serveur->getServerSocket().accept(client)!=0) {
             serveur->addConnection(client);
         }
         ::Sleep(1000);
      }
      return 0;
    }
    Ma classe ressemble à ça:
    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
     
    class CServeur : public CDocument {
      public 
         CServeur(int port);
         ~CServeur();
         void start();
         void stop();
         boolean restart(int port);
         boolean isStarted();
         int getPort();
         void setPort(int value);
         CSocket & getServerSocket();
     
      private:
         int port;
         boolean started;
         CSocket serverSocket;
         CWinThread *threadConnection;
         CWinThread *threadEcoute;
    }
    Voilà, en gros le socket est créer et détruit normalement, le socket est mis en écoute correctement avec CSocket::listen, mais la méthode CSocket::accept fais une erreur assertion. Merci d'avance.

  2. #2
    Membre confirmé Avatar de lenouvo
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    252
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 252
    Par défaut
    tu initialise bien tes sockets?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    			if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) {
    				AfxMessageBox("erreur AfxWinInit");
    			}
    sinon lorsque ton client se connecte, tu passe par l'ip ou le nom de ton serveur?
    le DNS peut avoir un peu de mal peut etre mais bon je pense pas que ca provoquerait une erreur d'assertion en fait

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 49
    Par défaut
    Non je fais pas ton initialisation. Mais ma l'essayer parce que je sais vraiment pas pourquoi dans le worker thread la méthode CSocket::accept fait une assertion. S'il y a d'autre suggestions bien dite le moi, car j'ai essayer de faire la meme chose,mais dans la méthode main(), et ça marche.

    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
     
    int main() {
      //Chargement des DLL nécessaires pour les winsock 2
      CSocket serveur;
      if (serveur.create(5555) && serveur.listen()) {
        Csocket *clients = NULL;
        while (true) {
          clients = new CSocket();
          if (serveur.accept(clients)) {
            cout << "Client accepter" << endl;
            client->Shutdown();
          }
          delete clients;
          clients = NULL;
        }
      }
      return 0;
    }

  4. #4
    Membre confirmé Avatar de lenouvo
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    252
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 252
    Par défaut
    donc le pb viendrait de ton thread a priori.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 49
    Par défaut
    Oui, sa peux venir du Thread, mais je crois aussi que sa peu venir de MFC aussi car j'ai déjà eu des problèmes avec des update de fenetre. Sa ne m'étonnerais pas car MFC est un bon modèle de programmation, mais il n'est aps aussi flexible comme java et MVC.

    Il est imposible d'appeler updateData() a partir d'un thread comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    //Dans le thread
    this->setModifiedFlag()
    this->UpDateAllView(NULL);
     
    //Dans la vue
    CVIEW::OnUpdate() {
      viewValue =  getDocument().getValue();
      updateData(false);
    }
    Alors, si quelqu'un sais comment accepter des connexion dans un thread d'arriere plan(worker thread) faite le moi savoir. Merci....

  6. #6
    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
    Par défaut
    salut,tu n'en as pas besoin du thread ...
    les MFC utilisent une fenetre avec des notifications par messages pour les evenements sockets.
    l'acceptation d'une connection client devant se faire dans la fonction OnAccept de la socket d'ecoute.
    ce qui veut dire que tu dois avoir une classe derivée de CSocket pour la socket d'ecoute .
    un truc comme ça:
    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
     
    class CListeningSocket : public CSocket
    {
    	DECLARE_DYNAMIC(CListeningSocket);
    private:
    	CListeningSocket(const CListeningSocket& rSrc);         // no implementation
    	void operator=(const CListeningSocket& rSrc);  // no implementation
     
    // Construction
    public:
    	CListeningSocket(CMyClassExtern *pClassContext);// lien eventuel avec l'exterieur.
     
    // Attributes
    public:
    CMyClassExtern *m_pClassContext;
     
    // Overridable callbacks
    protected:
    	virtual void OnAccept(int nErrorCode);
     
    // Implementation
    public:
    	virtual ~CListeningSocket();
     
    #ifdef _DEBUG
    	virtual void AssertValid() const;
    	virtual void Dump(CDumpContext& dc) const;
    #endif
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void CListeningSocket::OnAccept(int nErrorCode)
    {
    	CSocket::OnAccept(nErrorCode);
             m_pClassContext->ProcessPendingAccept(this);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    CMyClassExtern::ProcessPendingAccept(CListeningSocket *pServer)
    {
           CClientSocket* pSocket = new CClientSocket; // derivée de CSocket
    	if (pServer->Accept(*pSocket))
    	{								
    		pSocket->Init();		
    	}
    	else delete pSocket;
    bon c'est un exemple arrangé tres vite pour l'occasion.

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 394
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 394
    Par défaut
    Pour ce genre de chose, j'utiliserais directement CAsyncSocket : CSocket est une classe dérivée faite pour être bloquante...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 35
    Par défaut
    en fait il faut utilisé les threads fournit par les MFC, et AfxBeginThread, car les classes winsock utilisent des données locales qui ne sont pas renseignées en utilisant la fonction CreateThread.

    Il y a donc des assert en debug mais logiquement ça doit tourner.

    Il faut donc pour être propre, dérivé la classe CWinThread, et l'utiliser de préférence sans la pompe à message (le thread n'est à priori pas associé à une fenêtre....) et ça devrait supprimer les ASSERT...

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 49
    Par défaut
    Ok, je crois que je comprend ce que tu veux dire farscape, mais euh je veux pas que mon Serveur sois un socket, en tant que tel. Je voudrais eventuellement qu'il aye un interface graphique pour afficher les messages reçu/à transmettre ou faire des logs...etc Et pour ça je dois faire en sorte kil soit un Document et j'aimerais éviter kil y ait héritage multiple.

    Pour répondre à Médinoc, oui sa serais une bonen idée je crois, mais si je me souvient bien CAsyncSocket n'est pas bloquant et par le fait meme transmet des byte seulement, bref on peut pas faire de l'Archivage et c'est ce que ej veux faire..transmettre des Objet par réseau et possiblement les encrypter. **Encryption à implémenter plus tard, pas rendu là et je sais pas comment**

    Je pourrait faire en sorte par exemple que la class ListeningSocket aye un attribut CServeur(mon serveur) et que les Socket client sois dans cette class. De plus je n'aurais qu'un seul thread dans ma class CServeur et ce serais un thread qui parcours la liste des clients pour voir s'il y a des donner a lire? Est-ce un bonne idée? Merci d'avance

  10. #10
    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
    Par défaut
    Citation Envoyé par Philippe299
    Ok, je crois que je comprend ce que tu veux dire farscape, mais euh je veux pas que mon Serveur sois un socket, en tant que tel.
    j'ai jamais rien dit de tel ,j'ai parlé de la classe pas de son contexte d'utilisation.
    j'ai écrit un serveur de requêtes sur fichiers avec une interface graphique qui fonctionne de cette manière..
    voir les exemples MSDN CHATTER/CHATSRVR ( a chercher sur le site MSDN ou dans l'aide en ligne).

  11. #11
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 394
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 394
    Par défaut
    Pour répondre à Médinoc, oui sa serais une bonen idée je crois, mais si je me souvient bien CAsyncSocket n'est pas bloquant et par le fait meme transmet des byte seulement
    ???
    Qu'est-ce que tu appelles "transmet des byte seulement" ??
    Tu peux transmettre n'importe quoi qui tienne dans le buffer de transmission, et tu peux toujours transmettre en plusieurs parties...

    Et puis, tu peux toujours utiliser un socket d'écoute en CAsyncSocket et des sockets de travail bloquants...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 49
    Par défaut
    Bien, comment je peu dire ça sans fâcher des gens. J'aimerais aussi avoir des spécifications sur les CSockets. Tout ce que je veux envoyer sur le network c'est des objets et lire des objets, du "1010111010" binaire exactement. Je pense que des flux d'objet est ce que je dois utiliser, dite moi si j'ai tors.

    Deuxièmement, les méthode de CArchive comme readObject prenne un objet en paramètre et retourne un BOOL, est ce que readObject va retourner false si ya rien a lire ou elle va bloquer jusqu'a ce qu'il y a kekchose a lire. Je voudrais faire kekchose du genre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    for (int index=0;index<listClient.getSize();index++) {
      CClient *current = (CClient *)listClient[index];
      CObject *monObjet = NULL;
      if (current->getInput()->readObject(monObjet)) {
         //do something with the object
      }
    }

  13. #13
    Membre éclairé Avatar de philo71
    Profil pro
    Account manager
    Inscrit en
    Avril 2005
    Messages
    242
    Détails du profil
    Informations personnelles :
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Account manager

    Informations forums :
    Inscription : Avril 2005
    Messages : 242
    Par défaut socket
    J'ai un serveur qui marche en mode command donc sans mfc, il faut faire l'implémentation :

    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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
     
    #include "stdafx.h"
    #include <winsock2.h>
    #include <iostream>
     
    #include "serveur.h"
     
    #define _MAX_HOST_LENGTH_ 100
     
    using namespace std;
     
     
    //##ModelId=43A83B6B0132
    serveur::serveur(int p){
    	port	= p;
    	running	= false;
    }
     
    //##ModelId=43A83B6B013D
    int serveur::init(){    
    	struct in_addr  MyAddress;
    	struct hostent  *host;
    	char HostName[_MAX_HOST_LENGTH_];
    	WSADATA	      wsaData;
     
    	if(WSAStartup(MAKEWORD(2,2), &wsaData ) != 0 ){
    		cerr <<"WSAStartup a échoué "<< endl;
    		return 1;
    	}
     
    	if( gethostname( HostName, _MAX_HOST_LENGTH_ ) == SOCKET_ERROR ){
    		cerr<< "gethostname() a rencontre l'erreur "<< WSAGetLastError()  << endl;
    		return 1;
    	}
     
    	if( (host = gethostbyname( HostName ) ) == NULL){
    		cerr <<"gethostbyname() a rencontre l'erreur "<< WSAGetLastError()<< endl;
    		return 1;
    	}
     
    	memcpy( &MyAddress.s_addr, host->h_addr_list[0], sizeof( MyAddress.s_addr ) );
     
    	ServerAddr.sin_family = AF_INET;
    	ServerAddr.sin_port = htons( port );    
    	ServerAddr.sin_addr.s_addr = inet_addr( inet_ntoa( MyAddress ) );
     
    	cout <<"server correctement initialisé" << endl;    
    	return 0;   
    }
     
    //##ModelId=43A83B6B0146
    int serveur::start (){
    	SOCKADDR_IN                 ClientAddr;
    	int                         ClientAddrLen;
    	HANDLE                      hProcessThread;
    	SOCKET                      NewConnection;
    	struct thread_param         p;
     
    	if( ( ListeningSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ){
    		cerr << "ne peut creer la socket. Erreur n° " << WSAGetLastError()<< endl;
    		WSACleanup();
    		return 1;
    	} 
     
    	if( bind( ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof( ServerAddr ) ) == SOCKET_ERROR ){
    		cerr << "bind a echoue avec l'erreur " << WSAGetLastError() << endl;
    		cerr << "Le port est peut-être deja utilise par un autre processus " << endl;
    		closesocket( ListeningSocket );
    		WSACleanup();
    		return 1;
    	} 
     
    	if( listen( ListeningSocket, 5 ) == SOCKET_ERROR ){
    		cerr << "listen a echoue avec l'erreur " << WSAGetLastError() << endl;
    		closesocket( ListeningSocket );
    		WSACleanup();
    		return 1;
    	} 
     
    	cout << "serveur demarre : a l'ecoute du port : " << port << endl; 
    	running = true;
    	ClientAddrLen = sizeof( ClientAddr );
     
    	while(running){
     
    		if((NewConnection = accept( ListeningSocket, (SOCKADDR *) &ClientAddr, &ClientAddrLen)) == INVALID_SOCKET){
    			cerr  << "accept a echoue avec l'erreur " << WSAGetLastError() << endl;;
    			closesocket( ListeningSocket );
    			WSACleanup();
    			return 1;
    		}
     
    		p.ser = this;
    		p.soc = NewConnection;
     
    		cout << "client connecte ::  IP : " <<inet_ntoa( ClientAddr.sin_addr )<< " ,port = " <<ntohs( ClientAddr.sin_port ) << endl;
     
    		hProcessThread = CreateThread(NULL, 0,&serveur::ThreadLauncher, &p,0,NULL);
    		if ( hProcessThread == NULL ){                       
    			cerr << "CreateThread a echoue avec l'erreur " <<GetLastError()<< endl;
    		}
    	}
     
    	return 0;     
    }
     
    //##ModelId=43A83B6B0150
    int serveur::pause (){
    	running = false;
    	cout << "Serveur en pause" << endl;
    	closesocket( ListeningSocket ); 
    	return 0;
    }
     
    /* ======================================================================== */
    /* ========================== thread proc ================================= */
    /* ======================================================================== */
     
     
    //##ModelId=43A83B6B010A
    DWORD serveur::ClientThread(SOCKET soc){
    	cout << "thread client démarré" << endl;
     
    	/*    A mettre ici : code relatif au protocole utilisé    */
     
    	return 0;    
    }



    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
     
    #include "stdafx.h"
     
    #include "serveur.h" 
    #include <iostream> 
     
    using namespace std;
     
    int main(){
     
    	serveur *MyServer = new serveur(1234);
    	if(MyServer->init()!=0){
    		cerr << "ne peut initialiser le serveur"<< endl;
    		return 1;
    	}
     
    	if(MyServer->start()!=0){
    		cerr << "ne peut démarrer le serveur"<< endl;
    		return 1;
    	}
     
    	return 0;
    }

    Cdlt
    Philo

Discussions similaires

  1. Réponses: 18
    Dernier message: 13/04/2005, 15h46
  2. [MFC] Thread
    Par romeo9423 dans le forum MFC
    Réponses: 2
    Dernier message: 25/03/2005, 14h20
  3. [MFC] Thread & memory leaks
    Par Racailloux dans le forum MFC
    Réponses: 7
    Dernier message: 15/03/2005, 12h44
  4. [MFC] bouton avec option "accept files"
    Par bigboomshakala dans le forum MFC
    Réponses: 4
    Dernier message: 23/06/2004, 16h15
  5. Réponses: 3
    Dernier message: 11/02/2004, 12h50

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