Brauch ich nen neuen Thread/////CSocket



  • Hi Sven,
    Danke erstmal für deine Hilfe. Du hast die Schleife umgeschrieben, ist sicherlich eleganter jetzt. Aber das Problem liegt darin, dass die Message vom Server nicht in das m_strResult kommt.
    Nochmal: bevor die Funktion abläuft, die ich gepostet habe, setzte ich einen Socket m_Listen auf Listen. Der sorgt dann dafür, dass in die Variable m_strResult, die ich mit GetResult abfrage, das reinkommt, was er (über einen ClientSocket) empfangen hat.
    Einzeln kann man das über den Debugger überprüfen. Der m_Listen packt auf der einen Seite die Message in m_strResult. Auf der anderen Seite überprüft die gepostete Funktion was in m_strResult drin ist. Nur in der Synchronisation liegt das Problem. Ich befürchte, dass beides nicht parallel läuft.
    Jo



  • Ich weiß zwar nicht wo dein Problem liegt und was Sockets hier mit Sync. zu tun haben aber mal ne kurze Einführung in CAsyncSocket

    Du leites ein Klasse von CAsyncSocket ab und erstellst in ihr z.B.

    virtual void OnAccept(int nErrorCode);
    virtual void OnClose(int nErrorCode);
    virtual void OnReceive(int nErrorCode);
    Nun empängt diese Klasse Messages von CAsyncSocket
    Hier z.B.

    Wenn der Socket geschlossen oder etwas zum auslesen aus dem Socket bereit steht.
    Diese Message sendest du an deine Dialogklasse oder welche auch immer weiter um den Code zum auslesen des Sockets zu starten.

    Und mit der Memberfunc. von CAsyncSocket Receive ließt du das Empfangene aus.

    char ReadBuffer[256];
        char *FullData=NULL,*temp;
        int len,FullLen=0;
        len=pCurSocket->Receive(ReadBuffer,255);
        while(len>0)
        {
            temp=new char[FullLen+len+1];
            temp[FullLen+len]=0; //abschliessende 0
            if(FullLen!=0)
            {
                memcpy(temp,FullData,FullLen);
                delete FullData;
            }
            memcpy(temp+FullLen,ReadBuffer,len);
            FullData=temp;
            FullLen+=len;
            len=pCurSocket->Receive(ReadBuffer,256);
        }
        m_Receive.InsertString(0,FullData);
        if(FullData!=NULL)delete FullData;
        UpdateData(FALSE);
    


  • Also erstmal vielen Dank für eure Mühe.
    @Unix-Tom:
    So, wie das aussieht, schreibst du alle eingehenden Nachrichten in eine Variable. Ich brauch sie aber separat.
    Der ListeningSocket erzeugt bei mir bei jedem OnAccept() einen ClientSocket auf dem Heap, der mittels OnReceive etwas empfängt, weiterleitet an pParent (das CExchange-Objekt) und sich danach schließt. (Das FrontEnd empfängt nur Nachrichten, nachdem es selbst welche gesendet hat. Der Server erzeugt immer wieder einen neuen Socket, der connected und somit ein OnAccept() beim Client auslöst.)

    Mein Problem:
    Ich arbeite hier doch irgendwie von zwei Seiten:

    Mein CExchange Objekt, was allen Nachrichtenverkehr regelt, bekommt von irgendwoher den Auftrag, Daten für den Zweck GetRecordCount() zu besorgen.
    Nun tut CExchange folgendes.

    A)
    Es versetzt einen ListeningSocket in den Listen()-Zustand.
    (Der wartet auf Connections, erzeugt mit OnAccept() einen ClientSocket, der mit OnReceive() Nachrichten entgegennimmt und an das CExchange-Object weiterreicht.)

    😎
    Es sendet an den Server die Aufforderung, mal die Daten für GetRecordCount() einer bestimmten Tabelle an den Client zurückzusenden. Der Server macht das auch. (Die Daten landen auch im CExchange-Object an der richtigen Stelle.)
    Jetzt warte ich darauf, mit "return" die (über A) in das CExchange-Objekt eingegangen daten (z.B.: '5') zurückzuliefern, und zwar an die Instanz, die den Auftrag an das CExchange-Object gegeben hat. Ich warte mit Sleep() in 😎 darauf, dass A) seinen Job erledigt.

    Die beiden treffen da wieder zusammen, wo A) der Variablen m_strResult den Wert zuweist, den 😎 gerne zurückgeben will.
    Und genau das passiert nicht. A) und 😎 arbeiten einzeln gesehen korrekt. Es kommt aber nicht dazu, dass 😎 den Wert von A) zur richtigen Zeit auch erhält. Daher meine frage nach den Threads und der Synchronisation.
    Vielleicht kann ja doch noch jemand Licht ins Dunkel bringen.
    Euer CLoop



  • Ich verstehe jetzt nur mehr Bahnhof.

    Bezeichne deine Programme nicht mit Variablen oder Objekten sondern als Server und als Client.

    Du hast einen Server und einen Client.

    Der Server geht auf Listen und wartet auf eine Anforderung vom Client.
    Der Client führt einen Connect aus und der Server akzeptiert.
    Nun besteht ein Socket zwischen C/S.
    Über diesen können nun Daten in beide Richtungen versendet werden.
    Wenn es bis daher stimmt dann versuchen wir uns nun hier weiter zu bewegen.
    Nun kann z.B. der Client eine Anforderung nach einer Liste senden.
    Die empfängt der Server, liest seine Liste aus und sendet sie über den gleichen Socket wieder zum Server.
    Dieser sendet über den Socket , Liste empfangen und u.s.w.
    Hab ich was falsch verstanden ?

    [ Dieser Beitrag wurde am 10.01.2003 um 08:26 Uhr von Unix-Tom editiert. ]



  • Hi Unix-Tom,
    danke für deine Mühe. Du hast die Client-Server-Struktur richtig verstanden.
    Ich muss aber irgendwie auf die Antwort vom Server warten, nachdem ich den "Request" losgeschickt habe. Ich hab das jetzt mal umgeschrieben und verwende den SendeSocket vom Client auch zum Empfangen:

    int CExchange::GetRecordCount()
    {
        /////////////SendeString zusammenbasteln
        CString strSend;
        strSend.Format("%d|",GETRECORDCOUNT);
    
            strSend += "loopback4000";     ///////Daten vom Client
        CAsyncSocket sSend;
    
        if(!sSend.Create())
        {
            MessageBox(NULL,"sSend konnte nicht kreiert werden!","Achtung!",
                MB_ICONEXCLAMATION);
            return -1;
        }
        sSend.Connect(m_strAddress,m_uiPort);    ///Daten vom Server
        /////////////////////Senden
    
        if(!sSend.Send((LPCTSTR) strSend,strSend.GetLength()))
        {
            MessageBox(NULL,"Sendevorgang unterbrochen!","Achtung!",
                MB_ICONEXCLAMATION);
            sSend.Close();
            return -1;
        }
    
        ///////Ergebnis abwarten
        char* pBuf=new char[512];
        int count=sSend.Receive(pBuf,512);
        while(count<=0  && m_iTry<40)
        {
            Sleep(50);
            m_iTry++;
            count=sSend.Receive(pBuf,512);
        }
            m_iTry=0;
        if(count>0)
            {
               pBuf[count]=0;
               int RecCount=atoi(pBuf);
               delete[] pBuf;
               return RecCount;
            }
            else
            {
               delete[] pBuf;
               return -1;
            }
    
    }
    

    Wenn man die While-Schliefe mit dem Debugger durchläuft bekommt man allerdings für count nur Nullen. Das ist hart.



  • Der Clientcode und der Servercode sollten vom Socket her gleich sein.

    Schau dir dazu mal www.mut.de ->> leseecke ->> VC++ 6 in 21 Tagen
    an

    Der Unterschied ist nur, daß der Server aus Listen und der Cleint auf Connect geht.
    Beide benutzen die gleiche Funktion zum Empfangen.

    Leite dir eine Klasse von CAsyncSocket ab.
    Somit bekommst du beim Client und bei Server eine Message wenn etwas am Socket passiert.

    Du brauchst bei Client nicht aus Listen gehen.



  • Im Zusammenhang gesehen ist der Quellcode von UnixTom etwas verständlicher
    LAN Verbindung Problem



  • Hi Leute,
    einmal möchte ich es noch versuchen!
    Ich bin vielleicht nicht der Imperator im Umgang mit Sockets und in sofern bin ich auch dankbar für jeden Hinweis.
    Ich bin aber der Meinung, dass es nicht daran liegt. Ich schreib euch jetzt mal den code für den Socket des Clients und den des Client (auszugsweise)

    void CSendSocket::OnReceive(int nErrorCode) 
    {
        // TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen
        if(nErrorCode!=0)
        {
            if(nErrorCode!=WSAEWOULDBLOCK)
            {
                CString string;
                string.Format("Could not receive! Error: %d",nErrorCode);
                MessageBox(NULL,string,"Achtung!",MB_ICONEXCLAMATION);
            }
        }
        else
        {
            char* pBuf = new char[1024];
            int count = Receive(pBuf,1024);
            if(count>0)
            {
                pBuf[count]=0;
                ((CExchange*) m_pParent)->SetResult(pBuf);
                m_strResult=pBuf;
            }
            delete[] pBuf;
        }
    
        CAsyncSocket::OnReceive(nErrorCode);
    }
    
    void CExchange::SetResult(char *pBuf)
    {
        m_strResult=pBuf;
        MessageBox(NULL,m_strResult,"",MB_OK);
    }
    
    int CExchange::GetRecordCount()
    {
        /////////////sendString zusammenbasteln
        CString strSend;
        strSend.Format("%d|",GETRECORDCOUNT);
        strSend += "|loopback4000";
    
        /////////////////////Senden
    
        if(!m_pSend->Send((LPCTSTR) strSend,strSend.GetLength()))
        {
            MessageBox(NULL,"Sendevorgang unterbrochen!","Achtung!",
                MB_ICONEXCLAMATION);
            return -1;
        }
    
        ///////Ergebnis abwarten
        while(m_pSend->m_strResult=="" && m_iTry<40)
        {
            Sleep(50);
            m_iTry++;
        }
    
        MessageBox(NULL,m_pSend->m_strResult,"aaaaaaaaa",MB_OK);
        return 0;
    
    }
    

    Wie man in CExchange::GetRecordCount() sieht, wird eine Aufforderung gesendet.
    Als nächstes geht die MessageBox auf, die in CExchange::SetResult implementiert ist (Aha, der Client hat was empfangen!), dann geht die MessageBox von CExchange::GetRecordCount() auf, und die ist leider leer. Das ist mein Problem.
    Ich hab daher schon den Socket an nen anderen Thread übergeben, hat alles nichts genützt. Obwohl der Socket nachweislich ein Datenpacket bekommt, kann ich es über CExchange offenbar nicht abfragen, egal, ob der Socket als Membervariable oder als global Variable definiert ist. Alles funktioniert, ich komm nur nicht rechtzeitig an die Werte ran, um sie mit GetRecordCount() noch zurückzugeben!
    Vielen Dank



  • In Deinem Fall würde ich ganz auf die Socket-Klassen verzichten und statt dessen socket, connect, send und recv verwenden.
    recv wartet im Normalfall bis Daten eingegangen sind, oder ein Socket-Timeout auftritt. Du kannst also ohne Thread arbeiten.



  • Du solltest nicht soviel mit Zeigern arbeiten die vermutlich nach delete nicht mehr gültig sind.

    In deiner von CAsyncSocket abegeleiteten Klassen in OnReceive

    if (nErrorCode == 0)
            ((CExchange*)m_pWnd)->OnReceive();
    

    In deiner Dialogklasse CExchange (Diese wenn es die Dialogklasse ist würde ich sowieso umbenennen auf z.B. CExchangeDlg) erstellst du eine Funktion OnReceive
    und in diser dann den Code vom mir weiter oben.
    Wie in VC++ 6 in 21 Tagen.



  • OK,
    Danke für die Tipps,
    ich werde es mal ausprobieren!



  • 🙂 🙂 🙂
    Hurra, es klappt.
    Mit dem Win32-Socket (socket,connect,recv etc.) klappt es so, wie ich mir das vorstelle.
    Danke Pfalzmarc, danke Unix-Tom 🙂 🙂 🙂


Anmelden zum Antworten