Geschwindigkeit von Netzwerknachrichten erhöhen
-
Mit größeren Nachrichtenblöcken dürftest du den Durchsatz ordentlich anheben können. Zumindest beim "realen" Versenden über Leitungen gibt es relativ viel Overhead pro Paket. Wie groß da das Ideal-Paket ist, weiß ich nicht, hängt eventuell auch noch von anderen Parametern ab.
Wenn bei dir Client und Server auf demselben Rechner laufen, könnte ich mir aber auch vorstellen, dass relativ viel vom System abhängt, UDP/TCP dürfte hier keine allzu große Rolle spielen, da eigentlich keine Pakete verloren gehen können.Edit: Es kann auch Einiges von der Programmierung von deinem Server und Client abhängen, vielleicht ist da noch Optimierungsbedarf?
-
Es ist vielleicht wenig, besonders weil beides auf dem Selbem Rechner ist, doch um die Menge der übertragenen Daten geht es dabei ja auch gar nicht so sehr, sondern um die Menge der Nachrichten.
Würde pro Nachricht mehr Byte übertragen mögen es vielleicht nicht mehr so viele Nachrichten sein, doch wohl durchaus eine größere Datenmenge.
Das Augenmerk bei Raknet liegt ja auf zeitkritische Aufgabenbereiche.
Wie z.B. bei nicht rundenbasierten Netzwerkspielen.Ich bin im Netzwerkbereich noch ein ziemlicher Anfänger und bin gerade mal soweit ein kleinen Chat gemacht zu haben, da ist es nicht so wichig möglichst Viele Nachrichten möglichst schnell zu übertragen.
Doch arbeite ich ja darauf hin meine kleinen Spielchen Netzwerkfähig zu machen und ich habe bis jetzt noch keinerlei Vorstellungen wie wichtig in diesem Bereich eine hohe Nachrichtenanzahl ist, weil bevor ich mir darüber den Kopf zerbreche wie ich meine Spielchen ein wenig umfunktioniere wollte ich erst allgemein mit der Netzwerkprogrammierung Erfahrungen sammeln.
Falls 1700 Nachrichten a 4 Byte für Zeitkritische Spiele (also viel Aktion, viele Kollisionsmöglichkeiten usw) weit mehr Nachrichten sind als ich brauche (so wie ich es dachte bevor ich die Raknetzahlen sah) soll es fürs Erste gut sein, aber dennoch wäre es dann noch interessant zu erfahren wie man Nachrichtenzahlen erhöht (vielleicht durch eine manuelle Limitierung auf X Byte pro nachricht (???), falls das so einfach geht).EDIT:
Dein Post hatte ich beim Verfassen diese Nachricht noch nicht gesehen Badestrand.Aber was meine Programmierung an Server und Client angeht.
Speziell für diesen Test habe ich alles ziemlich roh gestaltet, damit so wenig wie möglich vorhanden ist das die Verbindung behindern könnte.
Ich habe direkt im Quellcode die nötigen Strukturen schon mit den richtigen Portangaben und der IPadresse gefüllt. Keine Klasse oder sonstige ordnenden Strukturen.
Hab alles so roh wie es mir möglich war erstellt.
Das ist also alles in der Standardeinstellung mit möglichst wenig Zeug dazwischen.
-
ahh, stimmt, ich habe gerade nochmal nachgeschaut,.. minimale ethenet framelength ist 64byte,... (inkl. Fill-field)
also bei rund 1700 messages hast du aber immer noch nur rund 0,87 Mbit,..
d.h. wenn du beim aufstocken von 4byte bis rund 40 bytes eine veränderung der geschwindigkeit merkst, liegt das definitiv an deinem source/rechner,..(denk ich mal)
seid gegrüßt
-
Ich habe jetzt mal probiert 40 byte zu übertragen um zu schauen in wie weit sich die Anzahl ändert und das Ergebnis ist einfach nur Krank.
Wenn ich 4 Byte ständig hin und her schicke sind es immer noch unter 2000 Nachrichten erhöhe ich das auf 40 Byte sind es oft mehr als 25 000
Meine maximale Zahl war 33 000.
Nur stockt dann alles total bis ich entweder den Server oder den Clienten Schließe und somit den Nachrichtenaustausch stoppe.EDIT:
Bevor man jetzt auf die Idee kommt ich würde bei der Nachrichtenberechnung irgendein Blödsinn machen, soll gesagt sein, die Methode ist alles andere als geheimnisvoll.
ich habe eine globale intvariable (testzaehler) die zu Beginn auf 0 gesetzt wird.
Sobald der Nachrichtenaustausch beginnt (beginnt per Knopfdruck) wird testzaehler kontinuirlich um 1 erhöt wenn der Server recv() aufruft und eine Nachricht bekommt.
Drückt man beim Server auf eine Schaltfläche wird testzaehler wieder auf 0 gesetzt und ein Timer gestartet der der auf eine Sekunde gestellt ist.
Ist eine Sekunde vergangen wird der Wert von testzaehler ausgegeben.
-
ok,. poste mal deinen source,.
gruß
-
EDIT
buf ist ein chararray und os ein std::ostringstream
EDITDWORD wEvent, wError; SOCKET client; SOCKADDR_IN addr; WSADATA wsa; [...] WSAStartup(MAKEWORD(2,0), &wsa); client = socket( AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(12345); addr.sin_addr.S_un.S_addr = inet_addr("xxx.xx.x.xx"); connect(client, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN)); WSAAsyncSelect(client, modeless, WM_EIGENESETZWERK, FD_READ | FD_WRITE | FD_CONNECT | FD_ACCEPT | FD_CLOSE);Das passiert in der Main beim Klienten, alles so roh wie möglich und alles direkt eingegeben.
Analog für den Server:
DWORD wEvent, wError; SOCKET server; SOCKET client; SOCKADDR_IN addr; WSADATA wsa; [...] WSAStartup(MAKEWORD(2,0), &wsa); server = socket( AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(12345); addr.sin_addr.S_un.S_addr = ADDR_ANY; bind(server, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN)); listen(server, 8); WSAAsyncSelect(server, modeless, WM_EIGENESETZWERK, FD_READ | FD_WRITE | FD_CONNECT | FD_ACCEPT | FD_CLOSE);Und hier wird das ganze Nachrichtengedöns abgehandelt (für den clienten)
case WM_EIGENESETZWERK: wEvent = WSAGETSELECTEVENT(lParam); // d.h. LOWORD wError = WSAGETSELECTERROR(lParam); // d.h. HIWORD // Behandlung zweier für WSAAsyncSelect spezifizierte Ereignisse switch(wEvent) { case FD_ACCEPT: break; case FD_READ: recv(client, buf, 4, 0); // recv(client, buf, 40, 0); send(client, "aaa", 4, 0); // <- 4 byte-Version //send(client, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 40, 0); // <- 40 byteversion break;analog für den Server:
case WM_EIGENESETZWERK: wEvent = WSAGETSELECTEVENT(lParam); // d.h. LOWORD wError = WSAGETSELECTERROR(lParam); // d.h. HIWORD // Behandlung zweier für WSAAsyncSelect spezifizierte Ereignisse switch(wEvent) { case FD_ACCEPT: client = accept(server, 0, 0); break; case FD_READ: recv(client, buf, 4, 0); // recv(client, buf, 40, 0); testzaehler++; send(client, "aaa", 4, 0); //send(client, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 40, 0); // <- 40 byteversion break;// EDIT:
Wenn ich auf dem Button beim Server drückecase IDOK: os << testzaehler; SetWindowText(GetDlgItem(hDlg, IDC_STATIC2), os.str().c_str()); os.str(""); SetTimer(hDlg, 1, 1000, 0); testzaehler = 0; break;
-
Bei dem 40 byte-test war der buffer für recv zu klein

Das führte zum stocken, aber weshalb diese großen Nachrichtenzahlen?
Mit angepasstem Buffer bekomme ich bei 4 byete genau so viel nachrichten hin wie mit 40 byte sorry für den Fehler.
Das ist wohl so weil es eien 64 byte mindestlänge gibt wie du erwähntest.
So viel werde ich wohl nie brauchen, gibt es eine Möglichkeit diese zu ändern ohne dass ich in erfahrung bringen muss wie man sich ein eigenes Protoll schreibt?
An einer solchen Anpassung wird wohl der Unterschied liegen.
Wusste nicht dass es eine solche Mindestlänge gibt.
-
hmmm,..
1.)addr.sin_addr.S_un.S_addr = inet_addr("xxx.xx.x.xx");
ich hoffe das hast du nur ersetzt damit man deine i-net addy nich kennt,..

2.)
wieso hast du in einem Clienten einen fd_Set??3.)
passe doch deinen buffer an,...4.)
deinen accept befehlt verstehe ich nicht,.. der ist dochint accept(int s, struct sockaddr *addr, socklen_t *addrlen);5.)
ok, die warteschlange ist 8, acceptierst aber immer nur eine verbindung,
aber schliesst diese wieder nicht,...ich glaube der fd_set ist ohne schliessen der verbindung, bzw. nur eine verbindung zur gleichen zeit sinnlos, d.h. du hast log. immer mehr offene und AFAIR immer mehr nachrichten die gelesen werden wollen,..wenn du sie nicht schliesst,..
entweder nimmst du n array of sockets, bei accept natürlich neue zuweisen, invalide sofort diskonnecten,...
dann solltest du noch recv() auf null prüfen, denn dann wurde die gegenseite geschlossen bzw. -1 gabs n error,..
grüße
-
Hab nicht viel Ahnung von Internet/Netzwerken, mir wurde einfach mal gesagt ich soll das machen, weil man meine Internetip einfach rausfinden könne wenn man sich auskennt und wenn man dann in verbindung meine genaue lokale IP kenne gäbe es keine hürde mehr.
So wurde es mir zu mindest gesagt.
Und da es niemanden so schadet mache ich das einfach mal.Ich habe den geposteten Quellcode hier durchgeschaut, kann jedoch keine fd_set-Struktur entdecken oO.
Sollte dort jedoch eine sein und ich sehe die nur nicht, hat sie keine Funktion, denn ich verwende sie nicht und ist in dem Fall nur ein Überbleibsel früherer Tests(sofern da überhaupt noch eine ist, wo soll die denn sein?
Falls du diese FD-Nachrichten meinst, die hängen mit WSAASyncSelect zusammen und nicht mit einer fd_set-Struktur).Hab ich gemacht, das stocken war dann weg und es wurden nicht soviele Nachrichten versendet, aber genau so viele wie bei 4 byte.
Nun ja, der parameter s ist ja das Socket welches die Verbindungsanfrage enthält, die restlichen sind ja optional und da ich im Rahmen dieses Tests weder die IP des Clienten noch die größse der addr_in Struktur benötige sind die restlichen Parameter halt 0 und füllen nichts aus.
Zurückgegeben wird ja das (der?) Socket welcher die Anfrage gestellt hat (der client) und wird im Socket gespeichert der den Namen "client" trägt.Wie gesagt, dieses Programm ist ein reines Testprogramm zum zählen der Nachrichten.
diese 8 ist eine willkürliche Zahl gewesen die keinen besonderen Sinn hat, dort hätte genauso gut 1 oder auch 30 stehen können.
Ich brauche für diesen Test halt nur eine Verbindung, halt die des einen Clienten mit dem der Server die Nachrichten austauscht damit dieses Hin und her gezählt werden kann.
(und die fd_set-Struktur kann ich immer noch nicht finden).Und schließen brauche ich mein Socket auch nicht, das ist ein Testprogramm welches neben dem gepostetn gerade noch so viel Code enthält, sodass ich das alles komplilieren und ausführen kann. Wenn das Socket also geschlossen wird, dann deshalb, weil ich das Testprogramm selbst schließe.
recv brauche ich auch nicht auf 0 zu prüfen.
die FD_READ nachricht erhalte ich ausschließlich dann, wenn dort was zu lesen ist. Das hängt mit WSAAsyncSelect zusammen(so viel ich weiß ist das zu mindest so).
-
Ohne die Rückgabewerte von recv und send zu prüfen ist dein Code falsch. Du übergibst einen 4 Byte großen Puffer aber es kann sein das dieser nicht ganz gefüllt/verschickt wird.
Und ist dir bewußt das WSAAsyncSelect den Socket in den Non-Blocking Modus setzt?
-
Ja, mir scheint das der WSAAsync das äquidistante zum FD_set ist (daher die ähnlich mit FD_?)
das sorgt dafür dass das prog nicht wartet bis eine verbindung eingeht,..
nimm mal die WSAAsync struktur erstmal gänzlich raus, die benötigst Du nur falls du im nonblockingmodus arbeiten,.. beziehungsweise ein ganzes SET von eingehenden verbindungen quasi in einem stück abarbeiten willst,...lies dir dazu mal das tut von c-workers http://www.c-workers.ch durch um einen einfachen client und server im konsolenmodus zu erstellen,..
(copy n paste ?
)sei gegerüßt
-
Der Link funktioniert bei mir nicht :/.
Das ich durch WSAAsyncSelect im Nonblockingmodus arbeite wusste ich nicht, doch ist das ein großes Problem wenn sich sowieso Windows darum kümmert?
Also als Konsolenprogramm hatte ich ja schon einen Chat programmiert der der auch mehrere Clienten bedient (hier hatte ich wirklich fd_set verwendet).
Der Grund warum ich jetzt hier WSAASyncSelect verwende ist der,
dass ich in einem Windowsprogramm (mit DirectX und einem Winapi-Fenster) gerne eine Asynchrone Netzwerkverbindung hätte ohne selbst mit Threads oder sowas arbeiten zu müssen.
Ich lese immer wieder wie kompliziert das sei, dort vernünftig zu arbeiten.
Und weil cih sowieso für Windows programmiere (halt DirectX) hatte ich mir gedacht diese WindowsHilfsfunktionen tun nicht weh.Aber jetzt mal ganz unabhängig welche Methode ich jetzt verwende, gibt es eien Möglichkeit die Mindestpaketgröße zu ändern?
Hier wurde ja mal gesagt die Mindestgröße sei 64 byte.
Was könnte ich also tun um die Mindestgröße z.B. auf 4 byte zu setzen?Ab jetzt werde ich dann auch in solchen Tests den Rückgabewert prüfen, dachte eigentliclh immer, dass ein "Nichtganzfüllen" bei 4 byte eigentlich eine große Ausnahme wäre.
cu
-
Badestrand schrieb:
Wenn bei dir Client und Server auf demselben Rechner laufen, könnte ich mir aber auch vorstellen, dass relativ viel vom System abhängt, UDP/TCP dürfte hier keine allzu große Rolle spielen, da eigentlich keine Pakete verloren gehen können.
bei udp können schon pakete verloren gehen. ausserdem ist udp weit weniger komplex als tcp und die tatsache, dass man bei udp auf die prüfsummen verzichten kann, macht es nochmals 'ne ganze ecke schneller. aber grundsätzlich gilt für beide, dass man die pakete schön voll machen muss (bei tcp hat man leider wenig einfluss darauf), um guten durchsatz zu erreichen.

-
Kahino schrieb:
Das ich durch WSAAsyncSelect im Nonblockingmodus arbeite wusste ich nicht, doch ist das ein großes Problem wenn sich sowieso Windows darum kümmert?
Das heisst lediglich das Funktionen die unter normalen Umständen warten würden bis nen Timeout eintritt oder bis Daten da sind, SOCKET_ERROR mit WSAEWOULDBLOCK via WSAGetLastError() zurückliefern täten.
Aber da du Rückgabewerte von recv() etc. sowieso auswerten solltest weniger tragisch
Kahino schrieb:
Aber jetzt mal ganz unabhängig welche Methode ich jetzt verwende, gibt es eien Möglichkeit die Mindestpaketgröße zu ändern?
Nicht wirklich...
Man kann zwar mit setsockopt() an den Socket-Buffern rumschrauben, allerdings entsprechen die Socket-Buffergrößen nicht zwangsweise den TCP-Buffern.
Wobei ich meine da könnte man über irgendwelche Registry-Einträge was machen...Bei UDP können auch lokal Pakete verloren gehen, je nachdem wie schnell man die raus haut und beschäftigt das System so ist...