Frage zur Funktion recv



  • 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_Protocol

    Da 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 here

    S: 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
    }
    


  • http://vpn23.homelinux.org/

    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


Anmelden zum Antworten