(socket) problem bei empfangsfunktion



  • Du musst die Daten des Stringstreams schon noch in den String übertragen, den du da zurückgibst. Das passiert nicht automatisch, nur weil du den Stringstream mit dem String als Konstruktorparameter erzeugst.



  • wenn ich aber keinen stringstream mehr benutze, und trotzdem noch nix erscheint? (arbeite wie gesagt jetzt mit push_back())



  • Du erwartest, dass dir ein Text auf der Konsole ausgegeben wird, nicht?

    Das machst du ja nirgendwo anderst, als bei buff << c;

    Und wenn du das nicht drin hast, dann wird hald auch nichts ausgegeben. 🙄

    Im übrigen gibts du RecvBytes zurück, ohne etwas anderes, als eine einzige Zuweisung zu machen. (Sprich der Rückgabewert ist so nutzlos).



  • just-another-programmer schrieb:

    std::string RecvAllEx (int socket) //ich würd statt int SOCKET nehmen...
    {
    	std::string RecvBytes; //würd nen std::vector <char> nehmen... wenn du später damit weiterarbeiten willst vll auch deque, damit du die zeichen, die du vorn bearbeitet hast, besser "rausschmeißen" kannst...
    	char c; //ich würd ja mehrere bytes auf einmal versuchen, zu empfangen...
    	int result (0);
    	do
    	{
    		result = recv(socket, &c, 1, 0);
    		if (result == SOCKET_ERROR)
    		{
    			throw CreateSocketError();
    		}
    		else if (result)
    		{
    			RecvBytes.push_back (c);
    		}
    	} while (result);
    	return RecvBytes;
    }
    

    also meine lösung würde so aussehen:

    //global:
    const int recv_buffer_length (20); //size_t würde zwar an sich besser passen aber die winapi-fkt will ja nen int... mir war gerade mal nach 20 - hat nix zu bedeuten...
    
    std::deque <char> RecvAllEx (SOCKET socket)
    {
    	std::deque <char> RecvBytes;
    	char c[recv_buffer_length];
    	int RValue (0);
    	do
    	{
    		RValue = recv (socket, &c, recv_buffer_length, 0))
    		for (char *i (&c[0]), *e (&c[RValue]); i != e; ++i)
    		{
    			RecvBytes.push_back (*i);
    		}
    		if (RValue == SOCKET_ERROR)
    			throw CreateSocketError();
    	} while (RValue == recv_buffer_length);
    	return RecvBytes;
    }
    

    btw:

    MSDN schrieb:

    If no incoming data is available at the socket, the recv call blocks and waits for data to arrive according to the blocking rules defined for WSARecv with the MSG_PARTIAL flag not set unless the socket is nonblocking.

    heißt: du blockierst mit der funktion also so lange, bis die verbindung abbricht... kA, ob das ne tolle idee ist - aber du wirst scho wissen, was du machst ^^

    bb 🙂

    PS: Zu überlegen wäre auch noch - wenn du sehr viel empfängst, ob man das kopieren des strings/vectors/deque/.... irgendwie verhindern könnte...

    struct TRecv
    {
    //entweder, du nimmst "recv_buffer_length" hier als static member mit rein oder machst es so:
    std::deque <char> RecvBytes;
    TRecv (const SOCKET socket_nr, const int recv_buffer_length = 20) : RecvBytes (0)
    {
    	char *c buf = new char[recv_buffer_length];
    	int RValue (0);
    	do
    	{
    		RValue = recv (socket, &c, recv_buffer_length, 0))
    		for (char *i (c), *e (c + RValue); i != e; ++i)
    		{
    			RecvBytes.push_back (*i);
    		}
    		if (RValue == SOCKET_ERROR)
    			{
    				delete [] c;
    				throw CreateSocketError();
    			}
    	} while (RValue == recv_buffer_length);
    	delete [] c;
    }
    };
    

    wenn du es als template mit default-argument machst, kommste auch um den pointer an sich rum ^^

    TRecv temp (socketnummer);
    //temp.RecvBytes ...
    

    ist alles ungetestet - sollte aber hoffentlich (größten teils ^^) gehen ;o)

    tschö



  • oh.. das gefällt mir nich:

    for (char *i (&c[0]), *e (&c[RValue]); i != e; ++i)
            {
                RecvBytes.push_back (*i);
            }
    

    lieber so

    for (char *i=c,*e= (c+RValue); i != e; ++i)
              RecvBytes.push_back (*i);
    

    aber jedem das seine^^



  • bitte beim nächsten mal an einen aussagekräftigen Thread-Titel denken, damit andere Nutzer die Chance haben, über die Suchfunktion, geeignete Threads für ihr Problem zu finden.

    "warum funktioniert das nicht?" ist daher nicht unbedingt die erste Wahl 😉



  • hallo

    @ drakon: ahhh.. nee ich erwarte eben nicht von der funktion, dass der text auf der konsole ausgegeben wird. die funktion soll das empfangene in den string reinpacken und den dann zurückgeben.

    @unskilled: woah. danke, da werd ich mich jetzt mal durcharbeiten, mal sehn ob deine variante das macht, was ich möchte, sonst frag ich hier nochmal 😉

    @It0101: schon erledigt 🙂



  • hallo

    soo.. ich habe jetzt meine eigene funktion nochmal wie folgt bearbeitet:

    std::string RecvAllEx(int socket)
    {
    	string RecvBytes;
    	char c;
    	int result;
    	do
    	{
    		cout<<"empfange:";
    		result = recv(socket, &c, 1, 0);
    		if(result == 0 || c == '\0')
    		{
    			return RecvBytes;
    		}
    		cout<<c<<endl;
    		RecvBytes.push_back(c);
    		cout<<"recvbytes: "<<RecvBytes<<endl;
    		//cout<<c;
    
    	} while (result > 0);
    	throw CreateSocketError();
    }
    

    die ausgabe:

    empfange:d
    recvbytes: d
    empfange:i
    recvbytes: di
    empfange:e
    recvbytes: die
    empfange:
    recvbytes: die
    empfange:n
    recvbytes: die n
    empfange:a
    recvbytes: die na
    empfange:c
    recvbytes: die nac
    empfange:h
    recvbytes: die nach
    empfange:r
    recvbytes: die nachr
    empfange:i
    recvbytes: die nachri
    empfange:c
    recvbytes: die nachric
    empfange:h
    recvbytes: die nachrich
    empfange:t
    recvbytes: die nachricht
    empfange:
    recvbytes: die nachricht
    empfange:h
    recvbytes: die nachricht h
    empfange:i
    recvbytes: die nachricht hi
    empfange:e
    recvbytes: die nachricht hie
    empfange:r
    recvbytes: die nachricht hier
    empfange:r
    recvbytes: die nachricht hierr
    Socket-Fehler #10054: Eine vorhandene Verbindung wurde vom Remotehost geschlosse
    n.

    Drücken Sie eine beliebige Taste . . .

    das doppelte r entstand aber auch erst, als ich den client, der sendet, geschlossen hatte. also scheint er den char nochmal zu übernehmen und DANN erst die exception zu werfen.

    aber, das ist wirklich nicht das, was ich haben will. gibt es eine möglichkeit, dass ich die funktion nicht blockierend mache? oder gibt es eine möglichkeit, zu sagen: "hier ists vorbei"?

    greetz



  • just-another-programmer schrieb:

    soo.. ich habe jetzt meine eigene funktion nochmal wie folgt bearbeitet:

    std::string RecvAllEx(int socket) //warum nutzt du nicht SOCKET socket?
    {
    	string RecvBytes; //warum hier string und oben std::string?
    	char c;
    	int result;
    	do
    	{
    		cout<<"empfange:";
    		result = recv (socket, &c, 1, 0);
    		if (result == 0 || c == '\0') //würd ich nicht so machen - so verbaust du dir die möglichkeit, später doch mal was anderes, als strings zu versenden (dateien/....)
    		{
    			return RecvBytes;
    		}
    		cout<<c<<endl;
    		RecvBytes.push_back(c);
    		cout<<"recvbytes: "<<RecvBytes<<endl;
    		//cout<<c;
    	} while (result > 0); //!= SOCKET_ERROR...
    	throw CreateSocketError();
    }
    
    recvbytes: die nachricht hier
    empfange:r
    recvbytes: die nachricht hierr
    Socket-Fehler #10054: Eine vorhandene Verbindung wurde vom Remotehost geschlosse
    n.
    

    das hier liegt auch einfach mal daran, dass du es noch immer anders gemacht hast, als ich es gemacht hab...
    recv gibt nen SOCKET_ERROR wieder... c ist noch das vom letzten mal... => r wieder angehangen und erst dann wird die exception geworfen...

    aber, das ist wirklich nicht das, was ich haben will. gibt es eine möglichkeit, dass ich die funktion nicht blockierend mache? oder gibt es eine möglichkeit, zu sagen: "hier ists vorbei"?

    naja - um threads wirste ne rumkommen...

    aber:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-218469.html
    5. post oder so:

    unskilled schrieb:

    Es gibt auch WSAEvents - die kannste auslösen lassen, wenn du was empfängst...

    Also per WinAPI:

    WSAEventSelect (socket_number, wsa_event, FD_READ | FD_CLOSE)
    

    und dann nimmste nen Thread:

    unsigned __stdcall threadfunction (void *parameter)
    {
    //...
    WSAEvent wsa_event = static_cast <WSAEvent> (parameter);
    while (WAIT_TIMEOUT != WaitForSingleObject (wsa_event, INFINITE))
    {
    if (0 == recv (...))
     break; //disconnect
    }
    

    Mit Send machste es einfach so, dass du iwo nen string (oder besser nen std::deque <char>) hast und da das anfügst, was du senden willst und nen event setzt - dann übergibst du die beiden events in nem array dem thread und hast dort halt WaitForMultipleObject (events, INFINITE) - und guckst dann, welches event ausgelöst wurde - bei dem einen sendest du was, bei dem anderen guckst du, obs nen disconnect war (recv == 0) ansonsten empfängst du iwas und tust das halt in nen anderen container...

    der rest sollte von allein klar werden?!

    bb

    gibt auch noch ne winapi-fkt glaub ich...

    MSDN schrieb:

    select function [WinSock]

    int select(
    int nfds,
    fd_set* readfds,
    fd_set* writefds,
    fd_set* exceptfds,
    const struct timeval* timeout
    );

    Ist eigtl für viele SOCKETs gedacht... Also wirste nen Array von Sockets machen müssen ==> fd_set

    MSDN schrieb:

    fd_set structure [Winsock]
    typedef struct fd_set { u_int fd_count; SOCKET fd_array[FD_SETSIZE];
    } fd_set;

    die unsauberste Methode wäre meine von vorhin:

    const int recv_buffer_length (X);
    

    für X nimmst du dann nen wert, dessen vielfaches niemals auf einmal empfangen wird... also am besten ne rel. große primzahl - aber sie sollte halt auch nicht soo grß sein, dass du jedes ma mehrere mb speicher anforderst und dann nich ma en kilobyte brauchst ^^

    deine fkt noch mal:

    std::string RecvAllEx (const SOCKET socket)
    {
        std::string RecvBytes;
        char c;
        int result;
        for (;false;)
        {
            cout<<"empfange:";
            result = recv (socket, &c, 1, 0);
            if (result == SOCKET_ERROR)
                throw CreateSocketError();
            else if (result)
              {
                 std::cout << "Zeichen: " << c << std::endl;
                 RecvBytes.push_back (c);
                 std::cout << "RecvBytes: " << RecvBytes << std::endl;
                 continue;
              }
        }
        std::cout << "fertig... return:" << RecvBytes << std::endl;
        return RecvBytes;
    }
    

    warum machst du es nicht wenigstens mal so, wie ich schreibe? Oo

    bb - ich hoffe, du siehst noch durch ^^



  • for (;false;)
    

    rofl



  • hmm... wollte die schleife dann nich mehr ändern, weil ich am ende noch was gesehen hatte ><

    so wärs vll besser/schöner/was auch immer...

    std::string RecvAllEx (const SOCKET socket)
    {
        std::string RecvBytes;
        char c;
        int result (recv (socket, &c, 1, 0));
        while (result > 0)
        {
            RecvBytes.push_back (c);
            result = recv (socket, &c, 1, 0);
        }; //ich mag das semikolon hier ^^
        if (result == SOCKET_ERROR)
           throw CreateSocketError ();
        return RecvBytes;
    }
    

    bb


Anmelden zum Antworten