Socket-Server soll mehrere Clients akzeptieren!!!



  • also das beispiel finde ich programmiertechnisch sowieso etwas umständlich. der ist schon etwas älter, jetzt würde ich das so machen:

    OnSocket_Accept()
    {
    	CMySocket	 *mCurSock = new CMySocket();
    
    	m_oData.Add(mCurSock);
    
    	if (m_sListenSocket.Accept(*mCurSock))
    	{
    		// weiter machen ...
    	}
    }
    

    da haste dieses gewusel nicht mehr drin 😉

    ich bin mir nicht mal mehr ganz sicher was 'm_cConnData' genau war ^^ denke das sollte 'm_oData' gewesen sein o.ä.

    EDIT:
    aber das mit dem threads würde ich auch gerne noch wissen. habe eben meine anwendung getestet. da kommt auch nichts an, wenn socket eine funktion aufgerufen hat und diese noch nicht abgearbeitet ist. callback halt -.-

    würde nur gerne wissen wie man die sockets in einem eigenen thread ablaufen lässt. (wahrscheinlich wieder mal einfach als ich mir das vorstelle)



  • Danke klappt auch und sieht viel besser aus.
    Wenn ich mich recht erinnere würdest du dann jedem eine ID zuordnen.
    Wahrscheinlich im Abschnitt "weiter machen" oder ?

    OnSocket_Accept() 
    { 
        CMySocket     *mCurSock = new CMySocket(); 
    
        m_oData.Add(mCurSock); 
    
        if (m_sListenSocket.Accept(*mCurSock)) 
        { 
            // weiter machen ... 
    // Würdest du das dann so machen?
    static int nCounter;
    ++nCounter;
    mCurSock->m_iID = nCounter;
    // oder wie ?
        } 
    }
    


  • - leg dir einfach eine membervariable in deinem dialogfeld an, z.B. int iLastID.

    - im contruktor deines dialogfeldes setzt du diese auf 0

    jetzt in OnAccept():

    // ...
    // weiter machen ...
    
    mCurSock->iID = iLastID ++;
    

    jetzt bekommt jeder client ne andere id.

    das mit der id ist nur nen vorschlag. das must du selber entscheiden. je nach anwendung würde ich das anders machen. aber irgendetwas, was deinen client eindeutig identifiziert solltest du drin haben.

    @Unix-Tom: kannste mal nen beispiel posten wie das mit den threads aussieht? thx



  • Wofür noch eine ID? Den Socket Descriptor kann man doch zur Identifikation benutzen.



  • Hier gibts noch Beispielanwendungen, vielleicht hilft es ja: http://tangentsoft.net/wskfaq/examples/basics/index.html



  • danke fürs beispiel.

    ich habe mir das hier genauer angeschaut: http://tangentsoft.net/wskfaq/examples/basics/threaded-server.cpp

    aber jetzt bin ich mir unsicher:

    ich benutze in meinem programm für jeden client ein socket von CAsyncSocket.
    wenn ich threads einbaue, muss ich 'manuell' über Receive() gucken ob daten angekommen sind und ggf. behandeln.

    CAsyncSocket tut doch aber das gleiche, dann ist es doch doppelt gemoppelt, oder nicht?



  • Red Skall
    Leider kann ich dir deine Frage nicht beantworten(weiss es selbst nicht).
    Wäre aber coll wenn jemand dafür eine Lösung hat.

    Ich habe aber noch ein Problem mit OnReceive.
    Wenn ich in Accept alle Client annehme und ihnen eine Id zuweise wie kann ich in OnReceive heraus finden welcher Client mit gerade etwas sendet.
    Also wie müsste ich folgende Zeile aus dem Prog vom Buch Visual C++ in 21 Tagen ändern damit es funktioniert.

    // Nachricht empfangen
      iRcvd = m_sConnectSocket.Receive(pBuf, iBufSize);
      // Haben wir etwas empfangen?
      if (iRcvd == SOCKET_ERROR)
      {
      }
      else
      {
        // Ende der Nachricht abschneiden
        pBuf[iRcvd] = '\0';
        // Nachricht in einen CString kopieren
        strRecvd = pBuf;
        // Nachricht in Listenfeld Empfangen eintragen
        m_ctlRecvd.AddString(strRecvd);
        // Variablen mit Steuerelementen synchronisieren
        UpdateData(FALSE);
      }
    

    m_sConnectSocket habe ich nach dem neuen Code ja nicht mehr sondern sie alle im ObArray gespeichert.
    Ich hoffe du verstehst mein Problem.
    Mfg



  • deine OnReceive funktion im dialogfeld sieht jetzt so aus:

    void CDlgKlasse::OnReceive()
    {
    }
    

    vielleicht wird da noch ein errorcode übergeben, so genau habe ich das beispiel nicht mehr im kopf.

    die funktion änderst du jetzt folgendermaßen:

    void CDlgKlasse::OnReceive(CMySocket *mSock)
    {
    }
    

    in deiner socketklasse rufst du die funktion deines hauptdialogfeldes nicht mehr ohne parameter auf, sondern so:

    void CMySocket::OnReceive()
    {
        m_DialogfeldKlasse->OnReceive(this);
    }
    

    jetzt wird die adresse vom socket übergeben, der etwas enpfängt. im hauptdialog kannst du die id einfach aus dem übergebenen objekt deiner socket klasse entnehmen.



  • In der Receive funktion mache ich dann folgendes:

    char *pBuf = new char[1025];
    	int iBufSize = 1024;
    	int iRcvd;
    	CString strRecvd;
    // Nachricht empfangen
    	iRcvd = mSock->Receive(pBuf, iBufSize);
    

    Doch das gibt Problem mit dem Aufruf

    GetDocument()
    

    denn ich später in OnReceive aufrufe.
    Woran kann das liegen?
    bzw.
    Wie hast du das mit der Funktion:

    // Nachricht empfangen
    	iRcvd = mSock->Receive(pBuf, iBufSize);
    

    gelöst?
    Mfg



  • Bau mal eine Anwendung welche nur Sockets hat. Diese dann so das sie viele Clients akzeptiert.
    Du wirst dann sehen das in deiner Hauptklasse immer eine Funktion aufgerufen wird wenn Daten kommen.
    Diese Daten kannst du verarbeiten. Während dieser Verarbeitung wird deine Hauptklasse aber nicht mehr Informiert das Daten kommen bis die Verarbeitung fertig ist.
    Jetzt muss Du dir was einfallen lassen um diese Verarbeitung in einen Thread auszulagern um deine Hauptklasse wieder frei zu machen.

    Thread starten gibt es genug in der FAQ.
    Du startets einen Thread und übergibst ihm das was über den Socket gekommen ist.
    Dieser Thread verarbeitet und beendet sich wieder. Vielleicht auch noch den Aufrufer informieren darüber denn wenn du das Programm beendest bevor alle Threads beendet sind hast du ein Problem wenn du die einfach abschießt.
    Auch kann sich ja in der Zwischenzeit der Client disconnecten.
    Dh also du musst dir was einfallen lassen um die Threads auch zu steuern.
    DIeses Thema ist aber ein anderes als CAsyncSocket.
    CAsyncSocket heißt nur das die Socketfunktionen nicht blockierend sind und sofort wieder zurückkehren und ein Thread im Hintergrund den Rest für dich erledigt.



  • würde das gerno so lösen:

    es wird etwas empfangen, normalerweise wird jetzt OnReceive() der dialogklasse aufgerufen.

    statt dessen starte ich einen thread, aus der ich dann OnReceive() der dialogklasse aufrufe. theoretisch müsste OnReceive dann innerhalb des threads aufgerufen werden. während der abarbeitung der funktionen von OnReceive() können dann mehrere aufrufe dieser funktion von anderen sockets aufgerufen werden, ohne das es störungen geben würde.

    jeder socket startet dann ja auch nur den thread und kann sich wieder auf das empfangen von nachrichten konzentrieren.

    das müsste doch so möglich sein, oder ?



  • Möglich ist alles. Warum versuchst du es nicht einfach ob du mit Threads klar kommst und auch Sync kannst.



  • mit threads komme ich klar, wollte nur wissen ob das vom sinn her geht.

    aber das hab ich jetzt nicht verstanden ^^

    ... und auch Sync kannst.

    wie meinst du das?



  • Syncronisierung der Threads falls notwendig. Ob notwendig musst du wissen da du nicht von jedem Thread immer auf den Dialog oder sonstwas zugreifen darfs ohne zu sync.



  • sorry das ich mich jetzt so blöde anstelle 😉 aber was meinst du genau mit synchronisieren der threads ??



  • Critical Sections, Events ...



  • danke, da muss ich wohl noch etwas in der msdn wühlen.

    ich habe die threads eingebaut und es läuft eigentlich ganz gut. jetzt passiert aber etwas, was ich nicht verstehe:

    zu testzwecken sende ich von einem client eine nachricht zum server, welcher darauf reagiert, indem er viele einträge in eine datenbank schreibt (dauer der funktion ca. 20 sek).

    während dieser zeit sendet ein anderer client eine nachricht um zu sehen ob sie ankommt. aber sie kommt nur an, sobald die funktion mit dem datenbankeinträgen beendet ist !?

    in OnReceive wird ein thread aufgerufen, welcher die funktion im dualogfeld startet. OnReceive wird auch sofort nach aufruf des threads geschlossen, con daher müsste der socket eigentlich wieder auf nachrichteneingang prüfen.

    ich habe von zwei clients eine funktion aufrufen lassen, in der nur eine messagebox ausgegeben wird (ergebnis waren zwei messageboxen zur gleichen zeit). das heißt dann der thread wird aufgerufen und de rsocket kann weiter empfangen.

    hoffe das problem ist klar geworden 🙄



  • Habe ein ähnliches Problem
    und bin dank diesem Artikel schon weiter gekommen.
    Doch leider habe ich jetzt ein Problem.
    Zu meinem Prog.
    In OnAccept mache ich es wie im Artikel:

    void CAdoDatabaseView::OnAccept(void)
    {
        CMySocket *mCurSock = new CMySocket(); 
    
        m_oData.Add(mCurSock); 
    
        if (m_sListenSocket.Accept(*mCurSock)) 
        { 	
    		static int nCounter;
    
    		++nCounter;
    
    		mCurSock->m_iID = nCounter;
    
        }
    }
    

    In OnReceive erstelle ich dann die Threads wie folgt:

    void CMySocket::OnReceive(int nErrorCode)
    {
    	CWinThread *mCurThread = new CWinThread(); 
    
        m_oThreads.Add(mCurThread); 
    
    	mCurThread = AfxBeginThread(((CAdoDatabaseView*)m_pWnd)->ThreadFunc,NULL,THREAD_PRIORITY_NORMAL,0,0,NULL);
    }
    

    In meiner ThreadFunc rufe ich dann OnReceive auf wie folgt:

    UINT CAdoDatabaseView::ThreadFunc(LPVOID pParam)
    {
    
    	CAdoDatabaseView *pView    = (CAdoDatabaseView *)pParam; 
    
    	pView->OnReceive();}
    

    Mein Problem entsteht dann in meiner OnReceive funktion, denn ich weiß ja nicht für welchen Socket ich Receive aufrufe.
    Im Programm aus dem Buch "Visual C++ in 21 Tagen" steht:

    // Nachricht empfangen
    	iRcvd = m_sConnectSocket.Receive(pBuf, iBufSize);
    

    Doch wie bekomme ich den ConnectSocket heraus.
    In diesem Artikel über gibt man einfach "this" in der OnReceive Funktion. Doch ich erstelle ja jetzt eine Thread, kann man in dem vielleicht irgendwie den Socket speichern sodass man weiss welcher socket es gerade ist.
    Ich hoffe ihr versteht mich
    Mfg



  • dann speicher in deinem thread einfach die adresse deines aufrufenden sockets.

    wenn du es elegant lösen willst mit setter / getter methoden.

    @(D)Evil: bin ich meinem versprechen hiermit nachgekommen ?? ^^



  • Ja so etwas habe ich mir schon gedacht.
    Doch wie?
    Ich kann doch nicht einfach zu CWinThread eine Variable hinzufügen in der ich dann die addresse speichere oder?
    Code wäre super.
    Mfg


Anmelden zum Antworten