Server programmieren der mit mehreren Hundertausend Clienten klar kommt, Ideen?



  • Surkevin schrieb:

    Was denkst du/ihr wie das ICQ macht? Da sind auch mehrere Millionen drin 🙂

    aun wie vielen maschinen?
    IQC macht nur triviale sachen. text rein, sofort text raus. da muss eigentlich immer nur ein paket verarbeitet werden, oder? dann nimmt man IoCompletionPorts, nur ZWEI threads bei einer CPU und alles wird fein. da reichen einfach zwei.
    natürlich pro client einen socket. da gehen wir halt rauf, bis die eigene kiste schlapp macht. und dann kommen entweder proxies oder (ist aber schwieriger) gleich unabhängige knotenrechner.

    mh....ich mein wenn ichs komplett ohne Threads mache muss der letzte eben seine Zeit warten 😕

    jo, das geht bei ICQ prima, wenn ich mal unterstelle, daß die messages immer komplett als ein paket reinkommen.

    Oder ich erstell sagen wir 1000 Threads und mehr nicht...der Rest stellt sich hinten an bis ein Thread seinen Clienten abgefertigt hat (die Arbeit zwischen Server und Client sollte in etwa bei 3 Minuten liegen).

    ah, es wird fein. IoCompletionPorts sind genau die schnittstelle, daß ein pool von 500 threads auf einen port wartet(an dem meinetwegen 10000 sockets baumeln), und bei bei jedem signal wird halt der nächstmögliche thread freigemacht, aber nicht mehr als 500 gleichzeitig. und die größe performace hat man, wenn möglichst wenig umgeschaltet werden muss, deshalb bei sofortbeantwortbarem nur zweimal so viele threads wie cpus.
    das betriebssystem versucht sogar, gerde fertiggewordenen threads sofort neu einzustellen, um cache-effekte auszunutzen und lauter so anenehmen sachen.

    Warum findest du einen SOCKETvector schlecht? 🙂

    der wirrkt irgendwie unelegant, oder?

    Wenn du meinst ein Thread pro Socket, soll dieser dann endlos per read abfragen ob was ankommt? In dem Fall bräuchte ich nichtmal nen vector...wenn ein neues Accept kommt, neuer Thread + neuer Client.

    ja! so macht man es, wenn die verarbeitung nichttrivialer natur ist. wenn du nicht einfach nur jede anfrage sofort beantworten kannst, sondern das ganze sehr umständlich mit einloggen, verschiedenen menus und so ist. clients am computerspielserver sind gelegentlich sehr kompliziert. webserver sind gelegentlich sehr einfach.

    Das wäre in Ordnung oder?

    jo, ok. nur mßte dan aufpassen, daß das versenden der daten nicht zu schlimm bremst. wenn mein quattro pentium7 server mit 15G standleitung 1000 user mit isdn bedient, und jeder user nur 1M ziehen will, bleiben bei mir 1000 threads offen, jeweils so lange, bis der user endlich seine paar mckrigen bytes gesaugt hat.

    Und wenn die 1000 Threads erreicht sind muss man eben länger warten.

    wenn die 1000 isdn-leute länger als 30 sekunden brauchen, also ein neuer länger als 30 sek warten muß, machts keinen spaß mehr.

    falls du also sofortbeantworten kannst, wirds am besten. dann wirste natürlich kein synchrones write nehmen, und dein sendender thread ist sofort fertig (bereit für neues) (deswegen reichen 2 threads!).

    Hab grad probiert für jeden neuen Clienten einen Thread zu basteln, der ununterbrochen schaut ob Messages kommen. Naja das Ergebnis war ja zu erwarten, 100% CPU-Auslastung 🙄
    Wie kann man das besser machen? Mist Mist Mist 🙂

    polling? mesages? nie!!!
    warten mit WaitForSingleObject, WaitForMultileObject oder synchronem read. der server sollte ne konsolenanwendung sein.

    messages... sowas aber auch... tststs...

    mach estmal so:
    der hauptprozess wartet ja mit listen und macht neue sockets.
    pro neuem socket wird mit CreateThread ein neuer thread gestartet. übergeben wird dem neuen thread schlicht der neuen socket. dann kann der neue thread locker mit read und write arbeiten.



  • genau das hab ich ja gemacht, nur woher weiß der Thread ob was neues ankommt? Wie gesagt hab ichs per while(TRUE) gemacht und dann dauernd recv...aber das gibt mir natürlich eine Auslastung von 100%.....wie kann man hier WaitForSingleObject einbinden?
    Kevin



  • Surkevin schrieb:

    genau das hab ich ja gemacht, nur woher weiß der Thread ob was neues ankommt? Wie gesagt hab ichs per while(TRUE) gemacht und dann dauernd recv...aber das gibt mir natürlich eine Auslastung von 100%.....wie kann man hier WaitForSingleObject einbinden?
    Kevin

    warum hat recv nicht gewartet, wenn noch nix da war?
    "If no incoming data is available at the socket, the recv call blocks and waits for data to arrive ..."
    bei einem thread pro socket brauchste gar kein WaitForSingleObject. recv() sollte warten, ohne prozessorlast.
    haste irgendwo eingestellt, daß dein socket asynchron sein soll?



  • hier wahrscheinlich:

    WSAAsyncSelect(listenSocket, hwnd, WM_NOTIFY_SOCKET, FD_READ | FD_WRITE | FD_CONNECT | FD_ACCEPT);
    

    WSASyncSelect gibts aber nicht
    Kevin



  • Wie schalt ich den WSA denn Synchron?

    Kevin



  • Surkevin schrieb:

    hier wahrscheinlich:

    WSAAsyncSelect(listenSocket, hwnd, WM_NOTIFY_SOCKET, FD_READ | FD_WRITE | FD_CONNECT | FD_ACCEPT);
    

    WSASyncSelect gibts aber nicht
    Kevin

    lese ich da hwnd?
    das klingt nach nem window, das messages eschickt kriegen soll. besser isses, ein event zu nehmen, auf das man mit WaitForSingleObject warten kann!

    aber wichtiger: wozu select? mach doch einfach synchrones lesen!



  • Surkevin schrieb:

    Wie schalt ich den WSA denn Synchron?

    hab keinen demo-code mehr auf meiner platte.
    zeig am besten mal deinen und jemand wird schon sehen, warum der socket asynchron ist.



  • ok...wie gesagt ich denk es liegt am WSAAsyncSelect...aber wie krieg ich sonst die Messages dass ein Client connecten will? Ok...vielleicht nen acceptThread, der ja auch blockt...ma testen 🙂

    ZeroMemory(&wsaData, sizeof(WSADATA));
    	WORD wVersion = MAKEWORD(2, 0);
    	WSAStartup(wVersion, &wsaData);
    
    	listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    	if(!listenSocket)
    		return FALSE;
    
    	ZeroMemory(&sockadr, sizeof(SOCKADDR_IN));
    	sockadr.sin_family = AF_INET;
    	sockadr.sin_port = htons(2323);
    	sockadr.sin_addr.s_addr = INADDR_ANY;
    
    	bind(listenSocket, (LPSOCKADDR)&sockadr, sizeof(SOCKADDR_IN));
    
    	listen(listenSocket, 1);//SOMAXCONN);
    
    	WSAAsyncSelect(listenSocket, hwnd, WM_NOTIFY_SOCKET, FD_READ | FD_WRITE | FD_CONNECT | FD_ACCEPT);
    

    Kevin

    /edit:
    Mit dem Acceptthread funktionierts!! Kann mir bitte mal wer sagen wo die Unterschiede zwischen synchronen Sockets und asynchronen Sockets liegen? Danke 🙂

    Kevin



  • Ist damit nich dasselbe wie blocking bzw. non-blocking sockets ?

    blocking socket: Beispielsweise recv() wartet dann solange bis nen timeout eintritt (standardmäßig bei win glaube ich über ne Minute...) wenn keine Daten ankommen
    Bei nem non-blocking socket würde recv() wenn keine Daten ankommen sofort mit dem Fehler WSAEWOULDBLOCK zurückkehren.
    Bei ersterem wäre der Thread erstmal blockiert, bei zweiterem nicht.

    Umschalten zwischen blocking und non-blocking:

    unsigned long nonblocking;
    nonblocking=1; // Bei ungleich 0 wird der Socket auf non-blocking geschaltet.
    ioctlsocket(nenSocket,FIONBIO,&nonblocking);
    

    Bei Verwendung von WSAAsyncSelect() wird der Socket automatisch in den non-blocking Modus gesetzt und man bekommt eben nette Nachrichten sobald bei nem Socket was passiert 😃



  • kann man auch blocking mit den messages benutzen?



  • Surkevin schrieb:

    kann man auch blocking mit den messages benutzen?

    das wäre unfug.

    bei blcking (==synchron) wartet recv einfach so lange, bis was zu lesen da ist.

    bei nonblocking (==asyncron) wartet recv nicht, du kannst fein was anderes machen. aber mußt immer nachgucken ob messages kommen oder mußt auf ein event warten. und das nur, um bei ner message/event dann doch recv aufzurufen.

    du solltest blocking verwenden. es ist ja auch voll ok, daß der thread geblockt ist, solange er auf daten wartet. die anderen threads laufen ja weiter, wenn sie wollen.



  • ok dann danke ich euch mal 🙂





  • ich hab keine ahnung, was du im endeffekt anstellen willst...
    der eine edonkey server bedient 500k-800k leute und hat 12 gig ram.
    ich denke mal, da wird was mit raw sockets gemacht und die zuordnung der verbindungen vom programm selbst gelöst. also ip und port je endpunkt.



  • Wie haste denn den Thread noch ausgegraben? Das Programm wurde schon vor langer Zeit fertiggestellt 🙂 Danke trotzdem!



  • der eine edonkey server bedient 500k-800k leute und hat 12 gig ram.

    Quelle? Gibt es überhaupt soviele Leute die eMule/eMule nutzen? 🤡



  • wenn man das forum verzweifelt nach infos über threads absucht, dann kommt so einiges zu tage 😃
    die 500-800k leute sind fakt. im moment sind es 777k, mit 1M als maximum, und das auf dem größten server. die anderen bringen auch nochmal locker ne million zusammen. quelle: http://www.razorback2.com

    @Surkevin: was verrichtet das programm denn im endeffekt?



  • hi@all + volkard!

    ich progge auch grad einen chat server...
    ich mache das mit select...select blockiert ja bis etwas passiert: client adden, client message receiven....
    ich füge die neuen clients in einem vector ein, u wenn ein client eine message sendet wird mit FD_ISSET im vector nachgeschaut welcher client da was sendet...
    hab mal probiert 50 clients zu connecten...funzt prima ohne verzögerung (worst case 3 sekunden)

    ich arbeite ohne threads!
    was meint ihr zu der strategie? macht das icq auch so...ok der icq server gibt ja nur die online clients weiter? werden ja wohl kaum die messages über den icq server laufen? ich denk da wird zwischen den clients eine p2p connection erstellt? so wie auch beim filetransfer?

    cu



  • bei icq werden msg auch über den server geleitet oder zwischengespeichert.
    die haben bestimmt viel härtere maßnahmen, als wir das aus unserer "praxis" gewohnt sind 😃

    gruß



  • surf schrieb:

    ich füge die neuen clients in einem vector ein, u wenn ein client eine message sendet wird mit FD_ISSET im vector nachgeschaut welcher client da was sendet...
    hab mal probiert 50 clients zu connecten...funzt prima ohne verzögerung (worst case 3 sekunden)

    also etwa so?

    for (i = 0; i < NumSocks; i++){
                if (FD_ISSET(ServSock[i], &SockSet))
                    break;
            }
    

    naja, wie lahm wird dieser code bei 100000 clients?
    richtig, sehr lahm wird er.

    ich arbeite ohne threads!

    fein. aber durch die schleife um FD_ISSET wirste bei vielen clients ja lahmer als die thread-version.

    was meint ihr zu der strategie?

    ich halte nix davon.
    win schenkt und io completion ports und thread pooling. was du mit ohne threads und FD_ISSET machen kannst, geht auch mit io completion ports, nur schneller. sind die reaktionen auf die pakete wirklich trivial und mit kaum rechenzeit verbunden, könnten threadwechsel relativ teuer sein.

    macht das icq auch so...ok der icq server gibt ja nur die online clients weiter? werden ja wohl kaum die messages über den icq server laufen? ich denk da wird zwischen den clients eine p2p connection erstellt? so wie auch beim filetransfer?

    ich weiß nicht, wie icq das gelöst hat. ich weiß nur, wie ich es lösen würde. ich würde die messages über den icq-server laufen lassen, damit die teilnehmer sich nicht gegenseitig die ip-adressen ausspähen können und dann angriffe fahren. aber ich würde mir was überlegen, daß ich von anfang an mit mehreren servern rechne.


Anmelden zum Antworten