recv-Funktion

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
koax
Beiträge: 13
Registriert: Mi Okt 23, 2013 10:02 am

recv-Funktion

Beitrag von koax » Do Apr 24, 2014 10:54 am

Hallo,

meine TCP/IP Receivefunktion funktioniert nur im Debugmodus korrekt. Sprich wenn ich Einzelschritte ausführe, sieht select das Daten über den Socket anliegen, lass ich das Programm im execute durchlaufen, dann wartet select erst den Timeout ab und empfängt dann erst die Daten von recv. Bitte um Hilfe

Code: Alles auswählen

int Connection_recv(SOCKET sock, char* data_recv){
	
	int size_recv;
	char buffer[1024];
	int loop_recv=0;
	int c=0;
	int retselect;
	
	struct timeval time;
	fd_set fd;
	time.tv_sec = 5;
	time.tv_usec = 0;
    FD_ZERO(&fd);
	FD_SET(sock,&fd);
    
    
    printf("sock: %i\n",sock);
    do{  
    	retselect=select(sock, &fd, NULL, NULL, &time);   // null dann timeout,
    	if(retselect <1)
    		
    		printf("no answer until %d seconds\n",time.tv_sec);
    	
    	else{
    		
    		//printf("retselec: %d\n",retselect); //get answer =1 
    		size_recv = recv(sock, buffer+loop_recv, sizeof(buffer), 0);
    		
    		if(size_recv > 0){
    			
    			memcpy(data_recv,buffer, loop_recv+size_recv);
    			loop_recv+=size_recv;
    		}
    	
    		else if (size_recv == 0){ 
        	
					data_recv[loop_recv]= '\0';
        			return sock;
    			}
    			else{ 
        	
        			printf("recv failed: %d\n", WSAGetLastError());
        			return 0;
        		}	
		}
		
	}while(retselect > 0 );
	 
    printf("data_recv: %s\n",data_recv);
    
	
return sock;
}

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: recv-Funktion

Beitrag von cloidnerux » Do Apr 24, 2014 3:32 pm

Ich denke, das Problem liegt an an der Nutzung von select, sofern du unter Windows unterwegs bist, die ich so noch nie gesehen habe. Die Seite von M$ dazu: http://msdn.microsoft.com/de-de/library ... s.85).aspx
sagt mir, dass select die Anzahl der sockets zurück gibt, die bereit sind zu schreiben oder lesen, aber nicht ob da Daten anliegen?
Redundanz macht wiederholen unnötig.
quod erat expectandum

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: recv-Funktion

Beitrag von mfro » Do Apr 24, 2014 5:58 pm

koax hat geschrieben:Hallo,

meine TCP/IP Receivefunktion funktioniert nur im Debugmodus korrekt. Sprich wenn ich Einzelschritte ausführe, sieht select das Daten über den Socket anliegen, lass ich das Programm im execute durchlaufen, dann wartet select erst den Timeout ab und empfängt dann erst die Daten von recv. Bitte um Hilfe
Zumindest ein Problem ist wohl das da:

Code: Alles auswählen

... int Connection_recv(SOCKET sock, char* data_recv) {
...
    	retselect = select(sock, &fd, NULL, NULL, &time);   // null dann timeout,
select() erwartet als ersten Parameter die Anzahl der zu überwachenden Deskriptoren im zweiten Parameter und keinen Filedescriptor (der sich wohl hinter SOCKET versteckt).

Da gehört eine 1 hin.
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

koax
Beiträge: 13
Registriert: Mi Okt 23, 2013 10:02 am

Re: recv-Funktion

Beitrag von koax » Fr Apr 25, 2014 6:35 am

Das mit sock als ersten Parameter ist quatsch, das stimmt, der ist bei Windows garnicht benutzt, soweit ich das sehe.

Der Zweite Parameter muss doch auf die FD_SET - Struktur zeigen, damit ich dann bei select sehe ab wann auf dem Socket Daten anliegen und wann nicht(nonblocking sockets), oder bin ich da auf dem Holzweg?
@cloidnerux: wie würdest du dann eine nonblocking receivefunktion aufbauen?

Gruß

koax
Beiträge: 13
Registriert: Mi Okt 23, 2013 10:02 am

Re: recv-Funktion

Beitrag von koax » Fr Apr 25, 2014 7:07 am

ich glaube das Problem ist, das der Sender, nachdem er Daten gesendet hat, die Verbindung nicht sofort trennt(war aber in der Vergangenheit immer so, da hatte es auch geklappt). Jetzt läuft die do-while-Schleife zweimal durch, beim ersten Mal mit empfangen Daten, das zweite Mal unnütz und auf das Timeout wartend.

Code: Alles auswählen

...
do{  
    	printf("vorselect\n");
    	retselect=select(sock, &fd, NULL, NULL, &time);   // null dann timeout,
    	printf("retselect: %d\n",retselect);
    	printf("nachselect\n");
    	if(retselect <1)
...
vorselect
retselect: 1
nachselect
Bytes received: 8
data_recv: -62.265

vorselect
retselect: 0
nachselect
no answer until 2 seconds
data_recv: -62.265
Sollte ich in diesem Fall einfach auf blocking Sockets setzen und die Gefahr eingehen, das bei gestückelten Datensätzen nur die Hälfte empfangen wird oder den Timeout so klein wählen das es kaum auffällt das er da ist, man aber trotzdem noch kurz wartet falls doch noch ein zweiter Satz Daten ankommen(Performance schlecht).


EDIT:noch ein Problem, ist der Timeout 20000Mikrosekunden, gibt select null zurück, ist der Timeout 200000Mirkosekungen empfängt er was, aber läuft halt doppelt durch. ich verstehs nicht :(

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: recv-Funktion

Beitrag von cloidnerux » Fr Apr 25, 2014 9:56 am

@cloidnerux: wie würdest du dann eine nonblocking receivefunktion aufbauen?
Nach kurzer recherche, weil ich mit C/C++ noch nicht enorm viel mit Sockets gearbeitet habe, scheint die Lösung mit select doch der richtige weg zu sein, ich habe mich also geirrt:
http://www.codeproject.com/Questions/45 ... make-it-to
EDIT:noch ein Problem, ist der Timeout 20000Mikrosekunden, gibt select null zurück, ist der Timeout 200000Mirkosekungen empfängt er was, aber läuft halt doppelt durch. ich verstehs nicht :(
Ich glaube, du behandelst nicht alle Fehlerzustände korrekt.
Ich weiß nicht wie dein Sender aussieht, aber als Empfänger musst du damit rechnen, dass Nachrichten
gestückelt über mehrere Frames ankommen können, du also nicht immer den kompletten Datensatz in einem recv bekommst, die Frames Zeitverzögert oder bzw erst sehr viel später als erwartet ankommen, daher musst du mit langen Wartezeiten Rechnen. Zwischenzeitlich kann auch die Verbindung ordnungsgemäß beendet worden sein(senden eines FIN), daher werden keine weiteren Daten zurückgegeben. Es könnte aber auch zu einem Verbindungsabbruch(Kabel ziehen, Netzwerk fällt aus, etc) gekommen sein, was du nur durch den Timeout, bzw Heart-Beat funktionen mitbekommen kannst.

Zudem ist ja die Idee eines Timeouts, dass du nach einiger Zeit wieder die Kontrolle zurück gewinnst und den Zustand der Verbindung bewerten kannst. Du solltest also nie 30s in select warten, was ja auch wieder ein Blocking call ist, sondern nur einige Millisekunden, das Ergebnis von select auswerten und einen counter inkrementieren, um dann nach n-Iterationen(n*x skeunden) von der Programmlogik her das ganze abzubrechen.

Zudem ist das doch gewollt von dir, dass deine Schleife zwei mal durchläuft, oder etwa nicht?

Code: Alles auswählen

  }while(retselect > 0 );
Redundanz macht wiederholen unnötig.
quod erat expectandum

Antworten