Server programmieren der mit mehreren Hundertausend Clienten klar kommt, Ideen?
-
Hallo,
Ich überlege mir einen Server zu programmieren der mehrere Hundertausende Clienten abfertigen kann. Wo liegen hier die Probleme? Ich denke mir dass jeder Client eine Nummer zugewiesen bekommt, jede Nachricht des Clienten hat im Anfang ihre Nummer, abgetrennt durch irgendein Zeichen vom Rest...für jeden Clienten wird dann ein Thread erstellt und jeder Thread überprüft die empfangenen Daten, ob sie zum eigenen Clienten gehört. Wenn das der Fall ist geschieht hier die getrennte Abhandlung...nur wo liegen noch die Probleme? Ich denke ich werde sehr viel mit Mutexen arbeiten müssen. Was ich nicht weiß ist wie man dem Server klar macht, dass er überhaupt 1000 000 Clienten akzeptiert, also dass sie alle zum Server auf dem gleichen Port eine Verbindung herstellen können...habt ihr da eine Ahnung? Vielleicht auf FD_ACCEPT einfach den SOCKETvector um einen erweitern und den neuen SOCKET accepten lassen?Danke,
Kevin
-
Surkevin schrieb:
Ich überlege mir einen Server zu programmieren der mehrere Hundertausende Clienten abfertigen kann. Wo liegen hier die Probleme?
deine sockets sind sauteuer und die threads noch viel teurer.
probier doch mal, 10000 threads aufzumchen. meiner kackt so ungefähr bei 5000 ab und will einfach keine neuen mehr erzeugen. mag sein, daß du 10000 schaffst, aber ne mio nicht.
wenn deine aufgaben eher trivialer natur sind, kannste mal nachlesen über CreateIoCompletionPort und wie man das verwendet. wenn es reicht, daß der zustand der connection in ein paar variablen liegt.
wenn du echt so viele threads brauchst, wie connections, sehe ich aber eher schwarz.
kannst auf einer maschine auch nicht 1e6 connections aufmachen, das scahfft die leider nicht. die grenzen sind auch lächerlich niedrig.viele connections, beliebig viele connections kriegste vermutlich am saubersten hin, wenn du proxies zum bündeln benutzt, also dein hauptprozess redet gar nicht mit den kunden, sondern das macht ein dummer proxy, der alle pakete mit der kundennummer versieht und an den hauptprozess weiterleitet, die antworten entsprechend anhand der kundennummer zum richtigen kunden schickt.
kommt dann der wirtschafliche erfolg un du hast echt 1e6 kunden, stellste eben 1e2 proxies vor die tür.
oder du teilst den hauptprozess auf verschiedene maschinen auf. uih, das kann schwierig werden.
evtl nach linux umsteigen und clustern.Ich denke mir dass jeder Client eine Nummer zugewiesen bekommt, jede Nachricht des Clienten hat im Anfang ihre Nummer, abgetrennt durch irgendein Zeichen vom Rest...für jeden Clienten wird dann ein Thread erstellt und jeder Thread überprüft die empfangenen Daten, ob sie zum eigenen Clienten gehört. Wenn das der Fall ist geschieht hier die getrennte Abhandlung...nur wo liegen noch die Probleme? Ich denke ich werde sehr viel mit Mutexen arbeiten müssen. Was ich nicht weiß ist wie man dem Server klar macht, dass er überhaupt 1000 000 Clienten akzeptiert, also dass sie alle zum Server auf dem gleichen Port eine Verbindung herstellen können...habt ihr da eine Ahnung? Vielleicht auf FD_ACCEPT einfach den SOCKETvector um einen erweitern und den neuen SOCKET accepten lassen?
SOCKETvector? ich glaub', sowas nehmen wir besser nicht.
am besten für fette last sind IoCompletionPorts. aber die sind kompliziert. danach kommen schlicht ein thread pro socket. das ist einfach. der thread wartet einfach auf seinen socket durch synchrone aufrufe von read() oder so.vermutlich hilft thread pooling http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/thread_pooling.asp ungemein. das ist leicht zu coden und kling ganz vernünftig. ich habs aber noch nicht aufgemessen.
-
Mh naja 5000 isn bissl wenig

Was denkst du/ihr wie das ICQ macht? Da sind auch mehrere Millionen drin
mh....ich mein wenn ichs komplett ohne Threads mache muss der letzte eben seine Zeit warten
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). Warum findest du einen SOCKETvector schlecht? 
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. Das wäre in Ordnung oder? Und wenn die 1000 Threads erreicht sind muss man eben länger warten. Gut so oder gibts hier auch Probleme? Mhh...aber vielen Dank für die detaillierten Informationen!mfG
Kevin
/edit
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
Kevin
-
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?
Kevinwarum 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
Kevinlese 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

-
noch was zum lesen:
Meep Meep
-
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?