|
You last visited: Today at 18:25
Advertisement
recv - dynamischer Buffer
Discussion on recv - dynamischer Buffer within the C/C++ forum part of the Coders Den category.
11/28/2014, 01:33
|
#1
|
elite*gold: 55
Join Date: Mar 2006
Posts: 4,582
Received Thanks: 1,539
|
recv - dynamischer Buffer
Hallo, gibt es eine Möglichkeit den Buffer für recv Dynamisch zu machen ?
PHP Code:
bool CClient::ClientThread()
{
std::vector<char> szBuffer(65535);
int iReceivedBytes;
do
{
iReceivedBytes = recv(this->ClientSocket, szBuffer.data(), szBuffer.size(), 0);
if (iReceivedBytes <= 0)
{
closesocket(this->ClientSocket);
return 0;
}
this->PacketControl( szBuffer.data() );
} while (this->ClientSocket != INVALID_SOCKET);
return 0;
}
so benutze ich es momentan, aber ich finde das nicht wirklich schön so..
Hat jemand vielleicht eine Idee ?
|
|
|
11/28/2014, 17:58
|
#2
|
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,909
Received Thanks: 25,409
|
Nope, ist auch nicht sinnvoll. Willst du, dass dir das andere Ende den Speicher vollmüllen kann, wie es will? Es ist ja sowieso gängige Praxis ein gewisses Größenlimit für ein Packet im Protokoll festzusetzen - wieso sollte der Buffer da dynamisch sein? Ist ja nicht so, dass die Daten, die nicht in dieser Iteration in den Buffer passen, verloren gehen. Die liest man dann halt im nächsten Durchgang.
Ist ja beim Lesen von Dateien auch nicht anders, da gibt man ja auch an, wie viele Bytes man lesen möchte.
Eine Art konstanten Datenstrom wie beispielsweise std::cin kann man ja einfach als Wrapper um die lowlevel Funktionen implementieren.
|
|
|
12/04/2014, 09:22
|
#3
|
elite*gold: 0
Join Date: Apr 2010
Posts: 10,289
Received Thanks: 3,613
|
Alternativ kannst du erst zwei Bytes lesen welche für die Größe verantwortlich sind, anschließend dann anhand dieser zwei Bytes dir die die Länge des Packets verraten den Rest, solange eine gewisse Maximalgröße nicht überschritten wird.
|
|
|
12/04/2014, 13:49
|
#4
|
elite*gold: 1091
Join Date: Jun 2007
Posts: 19,836
Received Thanks: 7,180
|
Quote:
Originally Posted by Shawak
Alternativ kannst du erst zwei Bytes lesen welche für die Größe verantwortlich sind, anschließend dann anhand dieser zwei Bytes dir die die Länge des Packets verraten den Rest, solange eine gewisse Maximalgröße nicht überschritten wird.
|
^
Normalerweise haben Protokolle sowieso noch gewisse Zeichen festgelegt, die signalisieren dass eine Sequenz komplett/beendet ist. Du liest einfach so lange bis du das Zeichen hast die Daten ein und speicherst sie in einem anderen Vector den du auch außerhalb der Funktion nutzen kannst.
|
|
|
12/05/2014, 18:02
|
#5
|
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,909
Received Thanks: 25,409
|
In beiden Fällen hat man aber einen statischen Buffer, den man iterativ neu befüllt. Bloodx wollte wissen, ob man Daten empfangen kann, ohne eine maximale Buffergröße anzugeben. Zumindest entnehme ich das seiner Frage nach einem dynamischen Buffer und der Tatsache, dass er seine Schleife nicht schön findet.
Ob man die Trennung des Datenstroms dann mithilfe von magischen Trennsequenzen, statisch Packetgrößen oder einem Größenpräfix löst, ist ja sowieso dem Entwickler überlassen und hängt z.B. vom Anwendungsgebiet ab. Manche bieten sich gut für magische Sequenzen an, bei anderen passt das überhaupt nicht und ein Größenpräfix ist die Lösung.
|
|
|
12/05/2014, 18:42
|
#6
|
elite*gold: 55
Join Date: Mar 2006
Posts: 4,582
Received Thanks: 1,539
|
Ich benutze diese Funktion in einem Emulator.
Danke MrSm!th für deine erste Antwort, die war wirklich super !
Ich hatte bisher nur angst vor einem Overflow, darum ging es mir.
Wäre es Sinnvoll für die bekannten Packet's die Size zu prüfen einfach ? Das würde ja schon viele Sachen verhindern.
Ich kann ja also auch einfach
PHP Code:
if ( ( iReceivedBytes <= 0 ) || ( iReceivedBytes >= 1024 ) ) { closesocket( this->ClientSocket ); return 0; }
machen um direkt irgendwelche Phantasie Packets zu entfernen ?
Mit der Size auslesen hatte ich auch bereits überlegt, aber dann muss ich ja 2x recv'n ? Fand ich auch nicht sooo super, trotzdem Danke
|
|
|
12/05/2014, 20:28
|
#7
|
elite*gold: 1091
Join Date: Jun 2007
Posts: 19,836
Received Thanks: 7,180
|
Quote:
Originally Posted by MrSm!th
In beiden Fällen hat man aber einen statischen Buffer, den man iterativ neu befüllt. Bloodx wollte wissen, ob man Daten empfangen kann, ohne eine maximale Buffergröße anzugeben. Zumindest entnehme ich das seiner Frage nach einem dynamischen Buffer und der Tatsache, dass er seine Schleife nicht schön findet.
|
Wie willst du die Dynamik sonst hineinbringen? Du hast seine Frage ja schon korrekt beantwortet, Shawak und ich haben nur das ergänzt was für manche vielleicht nicht so offensichtlich ist.
@bloodx
Wieso willst du das Socket schließen wenn keine Bytes gelesen wurden? Ich kenne die Implementierung deiner Library nicht aber wenn du vom Socket liest und feststellst, dass dir inzwischen niemand etwas gesendet hat, wirst du vermutlich in diesem Moment 0 Bytes empfangen haben (weil 0 Bytes gelesen wurden). Möchtest du dann wirklich die Verbindung trennen?
Ob und wann ein Packet deinen Anforderungen nicht enspricht, entscheidest du. Wie ist eigentlich egal - du kannst auch den Inhalt prüfen.
|
|
|
12/05/2014, 20:50
|
#8
|
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,909
Received Thanks: 25,409
|
Quote:
Originally Posted by bloodx
Ich benutze diese Funktion in einem Emulator.
Danke MrSm!th für deine erste Antwort, die war wirklich super !
Ich hatte bisher nur angst vor einem Overflow, darum ging es mir.
Wäre es Sinnvoll für die bekannten Packet's die Size zu prüfen einfach ? Das würde ja schon viele Sachen verhindern.
Ich kann ja also auch einfach
PHP Code:
if ( ( iReceivedBytes <= 0 ) || ( iReceivedBytes >= 1024 ) ) { closesocket( this->ClientSocket ); return 0; }
machen um direkt irgendwelche Phantasie Packets zu entfernen ?
Mit der Size auslesen hatte ich auch bereits überlegt, aber dann muss ich ja 2x recv'n ? Fand ich auch nicht sooo super, trotzdem Danke 
|
Du scheinst die Funktionsweise von recv etwas misszuverstehen. Letztendlich kannst du das wirklich mit einer ReadFile Funktion vergleichen, nur dass du nicht von der Festplatte, sondern vom Netzwerkpuffer liest. Dabei blockiert die Funktion, wenn es nichts zu lesen gibt und hört dann auf zu lesen, wenn der aktuelle Lesevorgang beendet ist (die maximale von dir erlaubte Anzahl an Bytes wurde erreicht, die Verbindung wurde geschlossen, das System hat entschieden, dass erstmal genug empfangen wurde, ...), belässt die eventuellen restlichen Bytes im Puffer und macht dort beim nächst recv Aufruf direkt weiter. Diese Daten haben für send/recv keinerlei Struktur, es ist lediglich ein Strom von Bytes.
Wenn du auf der Senderseite 1 Packet (im Sinne deiner definierten Packetstruktur) verschickst, bedeutet das nicht zwangsläufig, dass es direkt in einem Stück ankommt. Ebenso bedeuten 2 Packets nicht gleich, dass du zwei recv Aufrufe brauchen wirst.
Du schreibst die Bytes auf der einen Seite in den Puffer rein und nimmst sie auf der anderen raus.
Worauf ich hinaus will: Wenn du mehr als 1024 Bytes im Puffer hast, heißt das nicht gleich, dass dort ein Fantasiepacket gesendet wurde. Es können auch einfach bereits mehrere Packets angekommen sein (sofern dein Protokoll nicht vorsieht, dass ein weiteres Packet erst nach einer Antwort des Servers kommen darf). Der Puffer, den du für recv als Zwischenspeicher angibst, ist nicht gleichzusetzen mit einem fertigen Packet; seine Größe ist ebenso wenig wie die Anzahl der empfangenen Bytes gleichzusetzen mit der Größe eines Packets. Es ist nur ein Zwischenspeicher. Die Packets musst du dir selbst zusammenbauen bzw. diesen Datenstrom sinnvoll in diese aufteilen.
Dementsprechend kann deine Struktur z.B. so aussehen:
Code:
const int MAX_DATA_SIZE = 100;
struct Packet
{
int magic_signature;
int protocol_version;
int packet_id;
int data_size;
char[MAX_DATA_SIZE];
};
Dein Puffer muss nun nicht zwingend sizeof(Packet) groß sein, du kannst aus Effizienzgründen durchaus mehr auf einmal lesen:
Code:
std::vector<Packet> received_packets;
const int MAX_BUFFER = 1024;
char buffer[MAX_BUFFER];
int buffer_pos = 0;
while ((int recv_bytes = recv(socket, buffer + buffer_pos, MAX_BUFFER - buffer_pos, 0) > 0)
{
int processed_bytes = 0;
//solange vollständige Packets extrahiert werden können
while (recv_bytes - processed_bytes >= sizeof(Packet))
{
Packet temp = *(Packet*)(buffer + processed_bytes);
if (temp.magic_signature == 1337 && temp.protocol_version == 1 && temp.data_size <= MAX_DATA_SIZE)
{
received_packets.push_back(temp);
}
else
{
//issue error
}
processed_bytes += sizeof(Packet);
}
//Rest an den Anfang des Puffers schieben und im nächsten Durchlauf weitermachen
memcpy(buffer, buffer + processed_bytes, recv_bytes - processed_bytes);
buffer_pos = recv_bytes - processed_bytes;
}
(ich weiß, ist kein schönes C++ bzw. ein C/C++ Mix, schlagt mich doch :<)
In diesem Beispiel habe ich der Einfachheit halber mit einer statischen Packetgröße gearbeitet (obwohl der genutzte Platz (data_size) innerhalb des Packets natürlich je nach Packet ID variieren kann).
Mit diesen fertig zerstückelten Packets kann man dann auch anständige Plausibilitätsprüfungen durchführen, so wie ich es dort exemplarisch mit ein paar typischen Bestandteilen eines Packets tue.
Quote:
|
Mit der Size auslesen hatte ich auch bereits überlegt, aber dann muss ich ja 2x recv'n ? Fand ich auch nicht sooo super, trotzdem Danke
|
Damit sollte auch das geklärt sein: Nein, musst du nicht. Du rufst recv immer gleich auf und das hat nichts mit der Anzahl oder der Größe von Packets zu tun. Du baust du dir erst aus dem empfangenen Strom zusammen und erst dort findet die Interpretation von irgendwelchen mitgesendeten Größen und was nicht alles statt.
received_packets kann dann an irgendwelche Callbacks zur Weiterverarbeitungen gegeben werden.
Quote:
|
Wie willst du die Dynamik sonst hineinbringen? Du hast seine Frage ja schon korrekt beantwortet, Shawak und ich haben nur das ergänzt was für manche vielleicht nicht so offensichtlich ist.
|
Gar nicht, der Puffer wird immer statisch bleiben.
Quote:
|
Wieso willst du das Socket schließen wenn keine Bytes gelesen wurden? Ich kenne die Implementierung deiner Library nicht aber wenn du vom Socket liest und feststellst, dass dir inzwischen niemand etwas gesendet hat, wirst du vermutlich in diesem Moment 0 Bytes empfangen haben (weil 0 Bytes gelesen wurden). Möchtest du dann wirklich die Verbindung trennen?
|
Wenn recv 0 zurückgibt, wurde die Verbindung von der anderen Seite geschlossen. Man kann nicht 0 Bytes empfangen, da recv eine blockierende Funktion ist, sprich sie wartet ggf. auf Input.
recv ist übrigens die Standardfunktion zum Empfangen auf Windows und Unix-Systemen.
|
|
|
12/05/2014, 20:58
|
#9
|
elite*gold: 1091
Join Date: Jun 2007
Posts: 19,836
Received Thanks: 7,180
|
Quote:
Originally Posted by MrSm!th
Gar nicht, der Puffer wird immer statisch bleiben. 
|
Streng genommen ja, aber wenn man den statischen Vektor in der Klasse schön pflegt, kann man sogar dynamisches Verhalten erzeugen (ändert natürlich nix daran dass er statisch ist). Das meinte ich damit, war vielleicht etwas blöd formuliert.
Quote:
Originally Posted by MrSm!th
Wenn recv 0 zurückgibt, wurde die Verbindung von der anderen Seite geschlossen. Man kann nicht 0 Bytes empfangen, da recv eine blockierende Funktion ist, sprich sie wartet ggf. auf Input.
|
Ah ok, bin von boost etwas anderes gewöhnt, da hatte ich immer die asynchronen Funktionen genutzt.
Quote:
Originally Posted by MrSm!th
recv ist übrigens die Standardfunktion zum Empfangen auf Windows und Unix-Systemen.
|
... die ich nie genutzt habe weil ich stattdessen fertige Netlibs wie die von boost genommen habe.
|
|
|
12/05/2014, 21:45
|
#10
|
elite*gold: 55
Join Date: Mar 2006
Posts: 4,582
Received Thanks: 1,539
|
Also ich zeig euch einfach mal wie das Abläuft bei mir.
PHP Code:
bool CServer::StartServer() { WSAData Data; if (WSAStartup(MAKEWORD(2, 2), &Data) != NULL) return 0;
this->m_Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (this->m_Socket == INVALID_SOCKET) { Log(MSG_FATALERROR, "Could not create a socket\n"); return 0; }
sockaddr_in Settings; Settings.sin_addr.s_addr = INADDR_ANY; Settings.sin_family = AF_INET; Settings.sin_port = htons(30001);
if (bind(this->m_Socket, (sockaddr *)&Settings, sizeof(Settings)) == SOCKET_ERROR) { Log(MSG_FATALERROR, "Could not bind the socket\n"); return 0; }
if (listen(this->m_Socket, SOMAXCONN) == SOCKET_ERROR) { Log(MSG_FATALERROR, "Could not Listen the socket\n"); return 0; }
std::thread t(&CServer::ConnectionThread,this); t.detach();
return 1; }
PHP Code:
void CServer::ConnectionThread() { bool bIsActive = true; Log(MSG_INFO, "\nCreated ConnectionThread\n"); SOCKET ClientSocket; do { ClientSocket = accept(this->m_Socket, nullptr, nullptr); if (ClientSocket == INVALID_SOCKET) continue;
CClient *Client = new CClient(ClientSocket);
} while ( bIsActive );
}
PHP Code:
CClient::CClient(SOCKET Socket) { this->ClientSocket = Socket; m_Database = new CDatabase(); m_Database->Connect("localhost", "xxxxx", "xxxxx", "xxxxx"); this->PlayerSession = new SPlayer; this->AccountSession = new SAccount;
std::thread t(&CClient::ClientThread,this); t.detach(); }
bool CClient::ClientThread() { std::vector<char> szBuffer(65535); int iReceivedBytes; do { iReceivedBytes = recv(this->ClientSocket, szBuffer.data(), szBuffer.size(), 0); if (iReceivedBytes <= 0) { closesocket(this->ClientSocket); return 0; } this->PacketControl( szBuffer.data() );
} while (this->ClientSocket != INVALID_SOCKET);
return 0; }
PHP Code:
bool CClient::PacketControl(char* Packet) { SPacketHeader PacketHeader = *(SPacketHeader *)(Packet); char *Data = new char[PacketHeader.Size]; memcpy(Data, (Packet + sizeof(SPacketHeader)), (PacketHeader.Size - sizeof(SPacketHeader)));
switch (PacketHeader.Type) { case 0x08: { char WelcomePacket[] = "\x1B\x00\x2A\xF0\xDE\x5C\x6D\x00\xD4\x4C\x7E\x44\xAA\x07\xD7\x46" "\x61\x1E\x00\x00\x00\x00\x00\x00\x01\x0F\x02"; send(this->ClientSocket, WelcomePacket, sizeof(WelcomePacket) - 1, 0); } break; case 0x02: return this->Login(Data, (PacketHeader.Size - sizeof(SPacketHeader))); case 0x09: break; // Version Check default: { for (int i = 0; i < PacketHeader.Size; i++) printf("%02X ", (BYTE)Packet[i]); printf("\n"); } break;
}
return 1; }
|
|
|
12/05/2014, 22:31
|
#11
|
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,909
Received Thanks: 25,409
|
Und was ist jetzt die Frage?
So wie du das machst, kann das übrigens ziemlich nach hinten losgehen. Zum einen erzeugst du ein Memory Leak (ich würde generell nicht mehr auf new/delete setzen, seit es C++11 gibt), zum anderen hast du keine Garantie, dass du ein vollständiges Packet in deinen Puffer bekommst, wie bereits oben erklärt. Deshalb musst du prüfen, ob du ein vollständiges und plausibles Packet hast.
|
|
|
 |
Similar Threads
|
[Selling] [SG] LV 87 Warrior 3P + LV 90 Buffer, Lv 76 Sura + lvl 70 Buffer
03/16/2014 - Metin2 Trading - 8 Replies
Hi,
Ich verkauf hier meine Chars auf Metin2.SG
Tradeadministrator :
dust oder wer online ist
Ingame name(en):
Kurdboy verheiratet mit Vexina, BugattiStyle verheiratet mit Custombuffer
|
Dynamischer Pointer wtf?
03/14/2014 - C/C++ - 4 Replies
Hallo,
ich brauche für ein Spiel 2 adressen. Diese sind dynamisch weswegen ich mich gleich an die pointersuche gemacht habe. Der 1 Pointer geht auch wunderbar, aber der 2 ist sozusagen statisch . Die Pointer zeigen einfach nach den neustart auf bullshit undzwa jeder von ihnen und der rest auf garnix.
Womit könnte das zu tuhen haben ?
|
[Realese] Flyff buffer für homepage buffer server
04/01/2011 - Flyff Private Server - 7 Replies
Hallo dies ist mein erstes tool ein flyff buffer für p-server die einen homepage buffer haben
1. den changejob ordner in eure appserv/www verschieben
http://biffi.bplaced.net/pic1.png
2. die config.html mit editor öffnen und eure ip eintragen
http://biffi.bplaced.net/pic2.png
|
Tinyproxy mit dynamischer IP
11/12/2010 - Technical Support - 3 Replies
Ich habe auf meinem Server tinyproxy laufen. Allerdings habe ich keine Lust, jedesmal, wenn sich meine IP ändert (jeden Tag!), die Configdatei anzupassen. Gibt es eine Möglichkeit, das zu umgehen?
Vielen Dank im Vorraus,
abba232
|
[Question] Hooking send() & recv() works, but recv hiding data for co???
05/06/2009 - CO2 Programming - 2 Replies
Hey guys, I've been making a DLL to allow another program to intercept the packets of conquer using windows pipes. (Then its the job of the main program to decrypt the packets, the DLL only gives a communication channel for the main program)
(winsock functions btw)
- hooking send() works fine for my internet browser
- hooking recv() works fine for my internet browser
- hooking send() works fine for conquer online
|
All times are GMT +1. The time now is 18:26.
|
|