recv() empfängt nicht alles



  • Hallo Leute
    Ich schreib mir gerade einen Server und stehe gerade vor dem Problem das wenn der Client eine Zeichenkette von unbekannter Länge sendet, wie kann ich dann mit meinem Server diese Zeichenkette empfangen? Ich will natürlich nicht das Puffer von recv auf 5 millionen schrauben...
    ich habs so versucht:

    char msg[20];
    	msg[0] ='\0';
    	int rc;
    	while((rc = recv(client, msg, sizeof(msg)-1, 0)) >0 ){
    		msg[rc] ='\0';
    		cout << msg;
    	}
    

    das wird zwar anstandslos compiliert aber sobald ich es ausführe bring mir vista das es "nicht mehr funktioniert..." an was liegt das?

    Danke



  • Es ist immer dasselbe...

    recv(..) kann "immer" zurückkehren... nach 1 Byte, nach 20 Bytes, ...

    Du brauchst eine Schleife und musst recv solange aufrufe, bis alles da ist was Du benötigst oder ein Fehler verursacht wurde... (rc == -1).

    Dann musst Du z.B. erst die Länge des Strings senden (z.B. int, 4 Bytes), auf der Gegenseite empfängst Du die Länge und empfängst danach soviele Bytes wie eben vorher übermittelt wurden.

    Oder Du machst ein Start / Stop Pattern...

    Simon



  • theta schrieb:

    Es ist immer dasselbe...

    Jopp.

    Natürlich würde Doku lesen + Gehirn einschalten vollkommen ausreichen, es zu verstehen. Aber wenn ich sehe wie oft das falsch gemacht/verstanden wird, denke ich mir, ... die Semantik von recv ist nicht praxisgerecht.

    Default = alles empfangen, mit derzeitigem Verhalten per Flag ("ALLOW_PARTIAL" oder so) auswählbar wäre vermutlich besser gewesen.



  • ja...

    boost::asio könnte das z.B.

    Simon



  • aber er nutzt doch ne schleife Oo

    char msg[20]; 
      msg[0] ='\0'; 
      int rc; 
      while((rc = recv(client, msg, sizeof(msg)-1, 0)) >0 )
      { 
        msg[rc] ='\0'; 
        cout << msg; 
      }
    

    kA, wieso hier iwas nicht gehen sollte...
    ich würds aber so machen:

    char msg[20]; 
      int rc; 
      while((rc = recv(client, msg, sizeof(msg), 0)) >0 )
      {
        cout << msg.write(msg, msg+rc);
      }
    

    das hier hab ich noch in meinem test-cpp-projekt gefunden, da hatte ma jmd nen http-socket bauen wollen und mir war langweilig 😉
    vll bringts dir ja was^^

    namespace sockets
    {
    	class http
    	{
    	private:
    		SOCKET sock;
    
    		static std::size_t counter;
    		enum { BUF_LEN = 1024 };
    
    		void connect(const std::string &ip)
    		{
    			SOCKADDR_IN sin;
    			sin.sin_family = AF_INET;
    			sin.sin_addr.s_addr = inet_addr(ip.c_str());
    			sin.sin_port = htons(80);
    
    			int error_code = ::connect(sock, (SOCKADDR *)&sin, sizeof(sin));
    			if(error_code == SOCKET_ERROR)
    			{
    				throw std::runtime_error("Cannot connect to " + ip);
    			}
    		}
    	public:
    		http()
    		:	sock(INVALID_SOCKET)
    		{
    			if(counter++ == 0)
    			{
    				WSADATA WSAdata;
    				WSAStartup(MAKEWORD(2,0), &WSAdata);
    			}
    
    			sock = socket(AF_INET, SOCK_STREAM, 0);
    			if(sock == INVALID_SOCKET)
    			{
    				throw std::runtime_error("Cannot create socket");
    			}
    		}
    
    		~http()
    		{
    		    closesocket(sock);
    
    			if(--counter > 0)
    				return;
    
    			WSACleanup();
    		}
    
    		void send(const std::string &ip, const std::string &request)
    		{
    			connect(ip);
    
    			int len;
    			for(std::string::size_type sent = 0, tosend(request.size()); sent != tosend; sent += len)
    			{
    
    				len = ::send(sock, request.c_str()+sent, tosend-sent+1, 0);
    				if(len == SOCKET_ERROR)
    				{
    					throw std::runtime_error("Cannot send request");
    				}
    			}
    		}
    
    		std::string recv()
    		{
    			char buf[BUF_LEN];
    
    			std::string R;
    			for( ;; )
    			{
    				const int length = ::recv(sock, &buf[0], BUF_LEN, 0);
    
    				if(length == 0)
    				{//	hier ist auch ne andere behandlung denkbar
    					throw std::runtime_error("Connection closed");
    				}
    				else if(length == SOCKET_ERROR)
    				{
    					if(GetLastError() == WSAEMSGSIZE)
    					{
    						R.append(&buf[0], &buf[BUF_LEN]);
    						continue;
    					}
    
    				//	hier evtl noch auf unterschiedliche errorcodes unterschiedlich reagieren...
    					throw std::runtime_error("failure at receive");
    				}
    				else
    				{
    					R.append(&buf[0], &buf[length]);
    					break;
    				}
    			}
    
    			return R;
    		}
    	};
    
    	std::size_t http::counter = 0;
    }
    

    bb



  • ...ich habe schlecht gelesen...
    simon



  • also ich habs jetzt...
    die schleife war schon richtig! aber ich hab dann folgendes geschrieben:

    WSADATA lpwsadata;
    	WSAStartup(MAKEWORD(2,0), &lpwsadata);
    

    und nicht mehr :

    LPWSADATA lpwsadata;
    	WSAStartup(MAKEWORD(2,0), lpwsadata);
    

    Weis auch nicht was da der Unterschied ist...



  • LPWSADATA lpwsadata; 
    WSAStartup(MAKEWORD(2,0), lpwsadata);
    

    erzeugt imho UB.
    http://msdn.microsoft.com/en-us/library/ms741563(VS.85).aspx
    ist also nur nen typedef auf nen Pointer auf WSADATA.
    Damit zeigt er nur irgendwo hin und beim lesen/schreiben darauf... bäm...

    bb

    edit: ich seh gerade, dass mein iwann aus langer weile mal geschriebener quellcode im regelfall auch nur einmal recv aufruft xD



  • unskilled schrieb:

    imho UB.

    limoblub?



  • undefined behaviour



  • UB = undefined behaviour...


Log in to reply