Frage zur Funktion recv
-
Okay, aber wie mache ich das wenn ich z.b. nicht weiss welche Daten ankommen?
Angenommen bei einem Chat ich weiss ja nicht was der andere z.b. mir schreiben möchte. (Ohne jetzt vielleicht irgendein Zeichen an das String Ende zu setzten um z.b. zu Kennzeichnen das ab dort der String zu Ende ist und alle Daten empfangen wuden. )Das mit dem Buffer füllen steht ja dann anscheind nicht richtig in der MSDN den in dem Beispiel wird der ja auch immer wieder vom Anfang aufgefüll.
do { iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0); if (iResult > 0) printf("Bytes received: %d\n", iResult); else if (iResult == 0) printf("Connection closed\n"); else printf("recv failed: %d\n", WSAGetLastError()); } while (iResult > 0);
-
recv__ schrieb:
Okay, aber wie mache ich das wenn ich z.b. nicht weiss welche Daten ankommen?
In dem Fall braucht man ein Protokoll. Eine ganz einfache Methode wäre zB. dass der Sender immer zuerst die Länge der folgenden Nachricht sendet. Der Empfänger liest diese Länge und weiß nun genau, wieviele Bytes zu der folgenden Nachricht gehören.
recv__ schrieb:
Das mit dem Buffer füllen steht ja dann anscheind nicht richtig in der MSDN den in dem Beispiel wird der ja auch immer wieder vom Anfang aufgefüll.
Das ist ja nur ein Beispiel, in dem die gelesenen Daten nicht weiter interpretiert/benutzt werden. Es wird lediglich die gelesene Byteanzahl ausgegeben. Wenn man die Daten wirklich braucht - was ja der Normalfall ist - sichert man sie vor dem nächsten Schleifendurchlauf, oder aber man verschiebt den Zeiger in den Puffer um die zuletzt gelesene Anzahl, wenn denn der Puffer groß genug ist.
-
Irgendwie weiss ich noch immer nicht wie ich das bei mir umsetzen soll.
Wenn ich mich am web.de Server anmelde dann gibt der Server zurück:Server: 220 web.de (mrweb102) Nemesis ESMTP Service ready
recv gibt als Länge 51 zurück.Damit könnte ich jetzt was zusammenbauen:
int i=0; do { rc = recv( MySocket, &Answer[i] , Answer.size() ,0); i=rc; } while ( rc != 51 ); cout<<"Server: " << &Answer[0] << endl;
Aber wie ist das bei Programmen wie Telnet implementiert?
Telnet weiss doch nicht wie groß die Daten sind die zurück kommen ...Belli schrieb:
Eine ganz einfache Methode wäre zB. dass der Sender immer zuerst die Länge der folgenden Nachricht sendet. Der Empfänger liest diese Länge und weiß nun genau, wieviele Bytes zu der folgenden Nachricht gehören.
Aber hier muss ich doch auch wenigstens eine Zahl empfangen oder kann man sagen bei kleinen strings z.b. bis 10 Zeichen die werden immer von recv empfangen?
-
Und wenn ich mich bei einem anderen Mailserver anmelde dann kann ich den Code schon wieder vergessen ...
int i=0; do { rc = recv( MySocket, &Answer[i] , Answer.size() ,0); i=rc; } while ( rc != 51 ); cout<<"Server: " << &Answer[0] << endl;
Irgendwie erscheint mir das alles total unlogisch.
-
Hallo,
ich arbeite auch gerade intensiv mit Winsock.
Ich glaube ich weiß worauf du hinaus willst...
Ich habe ein Progamm erstellt was mir eine Datei von einem Webserver abrufen soll. Da ich auch nicht weiß wie groß die Datei ist, muss es einen Weg geben das
herauszufinden.Und das ist im Protokoll festgelegt wo das Ende ist.
Nach meiner Anfrage erhalte ich Daten zurück die etwa so aussehen:
HTTP/1.1 200 OK Content-Length: 13388 Content-Type: image/jpeg Last-Modified: Tue, 17 Jan 2012 21:25:32 GMT Accept-Ranges: bytes 132 ETag: "0aed88a5ed5cc1:699" Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET Date: Sun, 15 Jul 2012 21:41:22 GMT Connection: close ÿØÿà JFIF
Das ist der Request vom Server. In Content-Length steht die reine Dateigröße.
13388 Bytes... Die Trennung zwischen diesen Daten und den Bilddaten erfolgt
durch zwei Zeilenumbrüche in Zeile 10 und 11.
Ab Zeile 12 Folgen die Daten für das Bild.Somit weiß ich wie groß die Datei ist und wo sie beginnt.
Mit dem Einlesen der Daten steht es oben ja schon richtig beschrieben.Du musst vor jedem recv() den Zeiger in deinem Puffer neu setzen um die Zeilen
versetzt soviele Bytes du schon empfangen hast, damit er alles schön hinter-
einander schreibt.Um das ganze nun auszuwerten musst du dir mit Stringfunktionen behelfen.
Wenn du auf so tiefer Ebene arbeitest musst du viel selber machen, hast aber auch
mehr Kontrolle.Schau dir nochmal das SMTP Protokoll an.
http://de.wikipedia.org/wiki/Simple_Mail_Transfer_ProtocolDa steckt schon ein System dahinter.
Wichtig sind die Zeilenumbrüche nach jedem Kommando.
Nicky
-
Naja, das mit den HTTP request und CONTENT-LENGTH etc. das kenne ich.
Ein schönes Beispiel habe ich gerade in der RFC entdeckt:
[code]
S: RCPT TO:Green@Beta.ARPA
R: 550 No such user hereS: RCPT TO:Brown@Beta.ARPA
R: 250 OK[/cpp]
Wenn ich RCPT TO:Green@Beta.ARPA an den Server sende dann weiss ich ja nicht ob ich ein 550 No such user here zurück bekomme oder ein 250 OK
Wie weiss ich also mit recv wann ich alles habe?
Das einzige was mir einfällt wäre zu überprüfen ob im Buffer drin steht:
No such user here oder 250 OK und wenn eines der beiden Sachen drin steht dann wurden alle Daten empfangen.
-
Indem du so lange recv() aufrufst und die Bytes an einen Puffer anhängst, bis du '\n' im Puffer hast?
-
Hallo nochmal,
darum die Stringfunktionen mit denen auf das Vorhandensein bestimmter
Zeichen prüfen kannst...Wenn du nur "10 Bytes" erwartest, kannst du davon ausgehen das diese in
einem Rutsch da sind, da TCP Paketweise überträgt.Was auch für dich von Vorteil währe, ist die Funktion WSAAsyncSelect().
Damit wirst du benachrichtigt ob Daten angekommen sind, heißt du musst nicht
in einer Schleife dauernd abfragen.Somit kannst du auf jede "Frage" die richtige "Antwort" geben...
Ich habe ein Multiplayerspiel erstellt (Kniffel) für drei Spieler gleichzeitig.
Dafür musste ich mir ein eigenes Protokoll erstellen, damit die drei Clients
und der Server "richtig" reden können.Gruß, Nicky
-
Pseudocode:
function void SendLine(string msg) { send(socket,msg+"\r\n"); ... } function string RecvLine() { ByteListe puffer; // Bereits empfangene Bytes sammeln byte lastByte='x'; // Jeweils zuletzt empfangenes Byte merken do { lastByte=recvSingleByte(socket); // Einzelnes Byte empfangen puffer.append(lastByte); // Empfangenes Byte an den Puffer anhängen } while(lastByte!='\n') // Solange Bytes abrufen bis wir '\n' haben string zeile=WandleBytesInString(puffer); // Bytes in String umwandeln zeile=zeile.TrimEnd(); // Nutzloses Zeugs wie '\r', '\n' entfernen } // Kommunikation mit SMTP-Server: /////////////////////////////////////////////////////////////////////////// string resp=RecvLine(); // Banner vom Server "220 Server bla sagt willkommen" if (!resp.StartsWith("2")) { // Server hat nicht mit Statuscode 2xx geantwortet } // Hallo zum Server sagen: SendLine("HELO i.am.client.example.org"); // Antwort empfangen: resp=RecvLine(); if (!resp.StartsWith("2")) { // Server hat nicht mit Statuscode 2xx geantwortet }
-
Schau mal die kleine (SMTP library - SMTPLIBEX v0.02) Library an und probiere es zu verstehen. Die Library ist nach RFC 821/2821 implementiert. Zurzeit leider noch im beta Stadium, aber stabil.
Zum Thema recv(). Wie meine Vorgänger schon gesagt haben kannst Du bei recv() nie wissen wieviel Du gerade empfangen wirst. Daher könnte die Funktion etwa so aussehen.
int RecvData(SOCKET sock ,char *rbuf ,int len) { int p = 0; int r = 0; int c = len; do { r = recv(sock ,&rbuf[p] ,c ,0); if(r == SOCKET_ERROR) { return SOCKET_ERROR; } if(r == 0) { return p; } p += r; c -= r; } while(p != len); return p; }
-
Da es ein WinApi-Forum ist hier wie recv funktioniert:
http://msdn.microsoft.com/en-us/library/ms740121.aspx
Hier wird beschrieben, das recv so wie viel an Bytes liefert wie möglich (Angebot). Maximal natürlich buffer_size.Beispiel aus der MSDN. Man achte aufs Fehlerhandling
#define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <Ws2tcpip.h> #include <stdio.h> // Link with ws2_32.lib #pragma comment(lib, "Ws2_32.lib") #define DEFAULT_BUFLEN 512 #define DEFAULT_PORT "27015" int __cdecl main() { //---------------------- // Declare and initialize variables. WSADATA wsaData; int iResult; SOCKET ConnectSocket = INVALID_SOCKET; struct sockaddr_in clientService; char *sendbuf = "this is a test"; char recvbuf[DEFAULT_BUFLEN]; int recvbuflen = DEFAULT_BUFLEN; //---------------------- // Initialize Winsock iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != NO_ERROR) { printf("WSAStartup failed: %d\n", iResult); return 1; } //---------------------- // Create a SOCKET for connecting to server ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ConnectSocket == INVALID_SOCKET) { printf("Error at socket(): %ld\n", WSAGetLastError() ); WSACleanup(); return 1; } //---------------------- // The sockaddr_in structure specifies the address family, // IP address, and port of the server to be connected to. clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" ); clientService.sin_port = htons( 27015 ); //---------------------- // Connect to server. iResult = connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) ); if ( iResult == SOCKET_ERROR) { closesocket (ConnectSocket); printf("Unable to connect to server: %ld\n", WSAGetLastError()); WSACleanup(); return 1; } // Send an initial buffer iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 ); if (iResult == SOCKET_ERROR) { printf("send failed: %d\n", WSAGetLastError()); closesocket(ConnectSocket); WSACleanup(); return 1; } printf("Bytes Sent: %ld\n", iResult); // shutdown the connection since no more data will be sent iResult = shutdown(ConnectSocket, SD_SEND); if (iResult == SOCKET_ERROR) { printf("shutdown failed: %d\n", WSAGetLastError()); closesocket(ConnectSocket); WSACleanup(); return 1; } // Receive until the peer closes the connection do { iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0); if ( iResult > 0 ) printf("Bytes received: %d\n", iResult); else if ( iResult == 0 ) printf("Connection closed\n"); else printf("recv failed: %d\n", WSAGetLastError()); } while( iResult > 0 ); // cleanup closesocket(ConnectSocket); WSACleanup(); return 0; }
Enjoy it
-
Für Deine smpt-Fragen sollte Dir das Projekt helfen
[url]
http://www.codeproject.com/Articles/98355/SMTP-Client-with-SSL-TLS
[/url]
Ansonsten scchau Dich einfach mal auf codeproject um, da gibts noch mehr