recv() Empfangsproblem



  • Hallo,

    ich habe versucht aus Anleitungen ein Clientprogramm zu schreiben mit dem ich in ferner zukunft einen Matrixswitch schalten möchte. Das Problem ist das ich mit meinem Programm keinen Response erhalte vom Gerät, mit einem vorgefertigten Clientprogramm erhalte ich aber einen Response. Nehm ich aber ein vorgefertigtes Serverprogramm und sende eine Antwort an meinen Client dann empfängt der diesen auch, was kann das Problem sein, ist der Response zu schnell für mein Programm, hab ich irgendwas übersehen ?

    Hier der Quellcode:

    /*
    ######################################################################################
    
    testversion TCP client
    
    date of change:12.03.13 00:04
    
    Version: v1
    
    ######################################################################################
    */
    
    #include <winsock.h>
    #include <ansi_c.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    //#define IP "10.149.136.25"
    #define IP "192.168.1.1"
    #define PORT 333
    #define READBUF 1024 
    
    char a[2];
    
    int startWinsock(){
    	WSADATA wsa;
    	return WSAStartup(MAKEWORD(2,0),&wsa);
    }
    
    int Connection_build(SOCKET sock){
    
    	//SOCKET sock;	//Socketdescriptor
    	SOCKADDR_IN addr;
    	long ret;
    	int send_len;
    	char c_user_input;
    
    //start winsock
    	if((ret=startWinsock())!=0){
    		printf("failed to start winsock! code: %d\n",WSAGetLastError());
    	return 1;
    	}
    	else{
    		printf("winsock successfully started...\n");
    	}
    //genrate socket
    	if((sock = socket(AF_INET, SOCK_STREAM, 0))==INVALID_SOCKET){
    		printf("failed to generate sockets!\n");
    		return 1;
    	}
    	else{
    		printf("sockets successfully generated...\n");
    	}
    //fill struct SOCKADDR_IN with parameters: Adressfamilie, Ports(umgewandelt), IP
    	memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten 
    	addr.sin_family=AF_INET;
    	addr.sin_port=htons(PORT); 
    	addr.sin_addr.s_addr=inet_addr(IP); 
    
    //connecting
    	if((ret=connect(sock,(SOCKADDR*)&addr,sizeof(SOCKADDR)))==SOCKET_ERROR){
    		printf("failed to establish connection! code: %d\n",WSAGetLastError());
    		return 1;
    	}
    	else{
    		printf("connection established!\n");
    	}
    return sock;
    }
    
    int Connection_send(SOCKET sock, char c_user_input[256]){
    //send userinput
    	int send_len;
    	//char c_user_input[256]={"ACT-USER::root:1::root;"};
    	//char c_user_input[256];
    	int size_recv=0;
    	char buffer[1020]={"0"};
    
    	//printf("Eingabe: ");
    	//gets(c_user_input);   //userinput
    	printf("\n");
    	strcat(c_user_input,"\0");
    	//send_len=strlen(c_user_input)+2; //Länge herausfinden + Nullzeichen
    	send_len=strlen(c_user_input); //Länge herausfinden + Nullzeichen
    	if(send_len > 256){
    		printf("wrong determined input length!\n");
    		return 1;
    	}
    
    	if (send(sock, c_user_input, send_len, 0) != send_len){
    		printf("send() sent a different number of bytes than expected! code:%d\n",WSAGetLastError());
    	}
    
    	printf("send_len: %d\n",send_len);
    	//gets(a);
    
    //	size_recv = ClientTCPRead (sock, buffer, 500, 0);
    //	printf("Recv: %s\n", buffer);
    	size_recv = recv(sock, buffer, 1019, 0);
    	if (size_recv > 0)
    		buffer[size_recv] = '\0';
    	printf("Recv: %s\n", buffer);
    
    return sock;
    }
    
    int Connection_close(SOCKET sock){
    
    	closesocket(sock);
    	printf("socket closed");
    return 0;
    }
    
    int main(){
    	SOCKET sock;
    	sock=Connection_build(sock);
    	if(sock==1){					 // break if connection failed
    		gets(a);
    		return 1;
    		}
    	sock=Connection_send(sock, ":oxc:swit:conn:only (@2), (@81);*opc?");
    	//sock=Connection_send(sock, "ENT-PATCH::1,1:81:;");
    	Connection_close(sock);
    	gets(a);
    
    return 0;
    }
    


  • Achso, nehm ich eine vorgefertige TCP-Recv-Funktion dann bekomme ich als Rückgabewert -12 was heißt keine Connection established 😕



  • wenn mir jemand sagt, dass erstmal soweit nichts verkehrt ist würde das auch helfen



  • Ohne deinen Code jetzt genau angeschaut zu haben würde ich folgendes sagen:

    192.168.1.1. Gateway zu einer FritzBox?
    Du versuchst eine Verbindung zu der IP auf Port 333 herzustellen.
    Bis du dir sicher das auf dem Port überhaupt irgendwas auf eine Verbindung wartet? 😃

    Verwende mal als IP: 173.194.40.56
    Und als Port nimmst du: 80

    173.194.40.56 <-- IP von Google

    Dann funktioniert es, der Code scheint in Ordnung zu sein. (Hab ihn nicht Zeile für Zeile durchgeschaut sondern nur ob eine Verbindung hergestellt werden kann.)

    Du brauchst halt eine Anwendung die auf einem bestimmten Port auf eine Verbindung wartet.

    Les das hier mal: http://www.c-worker.ch/tuts.php

    Winsock Tutorial Teil 1, Grundlagen und TCP

    Das sollte momentan für dich interessant sein da steht auch wie du einen
    einfachen Server schreiben kannst. Am Ende von dem Artikel gibts die kompletten Sourcecodes auch als download.



  • Hi,

    die IP ist die Adresse des Gerätes mit dem ich sprechen möchte und die ist noch als Standart 192.168.0.1 festgelegt.

    Wenn ich mit einem fertigen clientProgramm dieses SCPI-command sende erhalte ich als Antwort eine "1" über den Port 333, also bin ich davon ausgegangen das der Port der richtige ist.

    Die Seite hat mir schon viel geholfen überhaupt erst soweit zu kommen wie ich bin 👍



  • Gut, ich habe mir jetzt schnell einen Servercode kopiert, der mir auf jede empfangene Nachricht sofort eine Antwort verschickt und siehe da mein Programm empfängt die Antwort sofort. Nur warum kann ich nicht mit dem Gerät kommunizieren... 😡



  • Also einen Bug sehe ich, ob das der einzige und der schuldige ist weiss ich nicht:

    int Connection_send(SOCKET sock, char c_user_input[256])
    {
    //...
    //...
    
        strcat(c_user_input,"\0"); // <--------------- geht so nicht
        //send_len=strlen(c_user_input)+2; //Länge herausfinden + Nullzeichen
        send_len=strlen(c_user_input); //Länge herausfinden + Nullzeichen
        if(send_len > 256){
            printf("wrong determined input length!\n");
            return 1;
        }
    
        if (send(sock, c_user_input, send_len, 0) != send_len){
            printf("send() sent a different number of bytes than expected! code:%d\n",WSAGetLastError());
        }
    

    * Du übergibst nen String-Literal als char* ( char blub[123] als Parameter ist genau das selbe wie char* blub ) und willst den dann mit strcat modifizieren. String-Literals modifiziert man nicht. Phöööse.

    • strcat(blub, "\0") macht genau gar nichts. Die Länge eines C-String definiert sich dadurch wann das erste Null-Byte kommt. "\0" ist zwar ein String-Literal der erstmal zu zwei Byte mit dem Wert 0 wird, nur strcat kann das nicht wissen, es sieht die erste 0 und da ist der String dann aus. D.h. strcat(blub, "\0") macht genau das selbe wie strcat(blub, "") , und strcat(blub, "") hängt einen leeren String an blub an, d.h. macht effektiv nix. Wenn du das Nullbyte mit verschicken willst, dann musst du einfach strlen(blub) + 1 übergeben.

    -->

    int Connection_send(SOCKET sock, const char* c_user_input)
    {
    //...
    //...
    
        send_len = strlen(c_user_input) + 1; //Länge herausfinden + Nullzeichen
        if(send_len > 256){
            printf("wrong determined input length!\n");
            return 1;
        }
    
        if (send(sock, c_user_input, send_len, 0) != send_len){
            printf("send() sent a different number of bytes than expected! code:%d\n",WSAGetLastError());
        }
    


  • Vielen Dank für die Info 👍

    Leider empfange ich immernoch keine Antwort



  • Vielleicht will das Gerät ja den String gar nicht mit \0 am Ende sondern mit \n oder gar \r\n?
    Oder es ist ein anderer Bug der aus dem Code den du hier gepostet hast nicht ersichtlich ist?

    Poste vielleicht nochmal 1:1 deinen aktuellen Code, und ebenso 1:1 was der für nen Output produziert.



  • Also der komplette Clientcode:

    /*
    ######################################################################################
    
    testversion TCP client
    
    date of change:12.03.13 00:04
    
    Version: v1
    
    ######################################################################################
    */
    
    #include <winsock.h>
    #include <ansi_c.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    //#define IP "10.149.136.25"
    #define IP "192.168.0.1"
    //#define IP "169.254.111.2"
    #define PORT 5025
    #define READBUF 1024 
    
    char a[2];
    
    int startWinsock(){
    	WSADATA wsa;
    	return WSAStartup(MAKEWORD(2,0),&wsa);
    }
    
    int Connection_build(SOCKET sock){
    
    	//SOCKET sock;	//Socketdescriptor
    	SOCKADDR_IN addr;
    	long ret;
    	int send_len;
    	char c_user_input;
    
    //start winsock
    	if((ret=startWinsock())!=0){
    		printf("failed to start winsock! code: %d\n",WSAGetLastError());
    	return 1;
    	}
    	else{
    		printf("winsock successfully started...\n");
    	}
    //genrate socket
    	if((sock = socket(AF_INET, SOCK_STREAM, 0))==INVALID_SOCKET){
    		printf("failed to generate sockets!\n");
    		return 1;
    	}
    	else{
    		printf("sockets successfully generated...\n");
    	}
    //fill struct SOCKADDR_IN with parameters: Adressfamilie, Ports(umgewandelt), IP
    	memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten 
    	addr.sin_family=AF_INET;
    	addr.sin_port=htons(PORT); 
    	addr.sin_addr.s_addr=inet_addr(IP); 
    
    //connecting
    	if((ret=connect(sock,(SOCKADDR*)&addr,sizeof(SOCKADDR)))==SOCKET_ERROR){
    		printf("failed to establish connection! code: %d\n",WSAGetLastError());
    		return 1;
    	}
    	else{
    		printf("connection established!\n");
    	}
    return sock;
    }
    
    int Connection_send(SOCKET sock, char* c_user_input){
    //send userinput
    	int send_len;
    	//char c_user_input[256]={"ACT-USER::root:1::root;"};
    	//char c_user_input[256];
    
    	//printf("Eingabe: ");
    	//gets(c_user_input);   //userinput
    	printf("\n");
    	//strcat(c_user_input,"\0");
    	//send_len=strlen(c_user_input)+2; //Länge herausfinden + Nullzeichen
    	send_len=strlen(c_user_input)+1; //Länge herausfinden + Nullzeichen
    	if(send_len > 256){
    		printf("wrong determined input length!\n");
    		return 1;
    	}
    
    	if (send(sock, c_user_input, send_len, 0) != send_len){
    		printf("send() sent a different number of bytes than expected! code:%d\n",WSAGetLastError());
    	}
    
    	printf("send_len: %d\n",send_len);
    	//gets(a);
    return sock;
    }
    
    int Connection_recv(SOCKET sock){
    
    	int size_recv;
    	char buffer[1024];
    
    	size_recv = recv(sock, buffer, 1024, 0);
    	if (size_recv > 0)
    		buffer[size_recv] = '\0';
    	printf("Recv: %s\n", buffer);
    
    return sock;
    }
    
    int Connection_close(SOCKET sock){
    
    	closesocket(sock);
    	printf("socket closed");
    return 0;
    }
    
    int main(){
    	SOCKET sock;
    	sock=Connection_build(sock);
    	if(sock==1){					 // break if connection failed
    		gets(a);
    		return 1;
    		}
    	sock=Connection_send(sock, ":oxc:swit:conn:only (@1), (@95);*opc?");
    	//sock=Connection_send(sock, "ENT-PATCH::1,1:81:;");
    	sock=Connection_recv(sock);
    	Connection_close(sock);
    	gets(a);
    
    return 0;
    }
    

    der Output dazu...

    winsock successfully started...
    sockets successfully generated...
    connection established!

    send_len: 38

    Der Cursor wartet dann eine Zeile unter send_len: 38 und da bleibt er auch

    Ich habe mit einem Portscanner das Gerät gescannt, offene ports sind 333, 5025, 9999 und 80. Mit dem fertigen Clientporgramm habe ich den Port 5025 getestet ,Commands senden funktioniert und ich bekomme eine Antwort.



  • hustbaer schrieb:

    Vielleicht will das Gerät ja den String gar nicht mit \0 am Ende sondern mit \n oder gar \r\n?

    klasse Kerl! es geht, ich brauchte ein new line damit der Command abgeschlossen wird, jetzt erhalte ich auch einen Response 😃

    tausend Dank 👍



  • Sehr gut. Und gleich merken.
    Bei textbasierten Protokollen ist \n oder \r\n als Abschluss sehr üblich.

    Und gleich nochwas: dein recv() ist mit an Wahrscheinlichkeit grenzender Sicherheit falsch. Standardfehler, macht jeder 2. Anfänger. Du musst, genau so wie der Server es macht, so lange lesen bis du den Terminator (vermutlich wieder \n ) empfangen hast. Einfach 1x recv() machen und hoffen dass alles in einem Rutsch ankommt funktioniert zwar oft - aber halt nur so lange bis es nicht mehr funktioniert. z.B. weil die Antwort mal etwas länger ausfällt, oder der Server etwas eigenwillig (aber nicht falsch) implementiert ist.



  • Wird gemerkt, thx!

    Das recv() wollte ich eh noch anpassen, hatte schon davon gelesen das manchmal etwas erst beim 2.Mal ankommen kann, mir war erstmal nur wichtig das überhaupt was ankommt 😃

    String-Literals modifiziert man nicht. Phöööse.

    Dass habe ich auf jedenfall noch nicht gerafft.



  • wäre dieser recv/select Aufbau so halbwegs in Ordnung?

    ...
    	struct timeval time;
    	fd_set fd;
    	time.tv_sec = 3;
    	time.tv_usec = 0;
    
       do{  
        	size_recv = recv(sock, buffer, sizeof(buffer), 0);
    
        	if (size_recv > 0){
    
        	for(c=0;c<size_recv; c++){
        			if(buffer[c]=='\n'){
        				printf("newline gefunden, raus aus der Schleife\n");
        				buffer[size_recv] = '\0';
            			printf("Bytes received: %d\n", size_recv);
            			printf("Recv: %s\n", buffer);
        				return sock;
        			}
        		}
        	}
        else if (size_recv == 0) 
            printf("Connection closed\n"); 
    
        else 
            printf("recv failed: %d\n", WSAGetLastError()); 
    
    	FD_ZERO(&fd);
    	FD_SET(sock,&fd);
    	retselect=select(sock, &fd, NULL, NULL, &time);   // null dann nichtmehr angekommen
    
    	}while(retselect != 0);
    


  • Nö, du musst schon die einzelnen empfangenen Bruchstücke zusammenhängen wenn du danach eine vollständige Nachricht haben willst.
    So überschreibst du ein empfangenes Bruchstück immer mit dem nächsten.

    Und das select() mit 3 Sekunden Timeout... huch?
    Willst du dass die Schleife abbricht wenn 3 Sekunden lang keine neuen Daten mehr ankommen?
    Wenn nicht, dann lass das select einfach weg.
    Und wenn schon, wieso verwendest du dann kein select() vor dem ersten recv() ? Was bringt mir ein cooles Receive-Timeout, wenn es nur nach dem ersten Paket greift?



  • Ok mit dem ersten Teil hab ich schon vermutet.

    Ich dachte mir 3 Sekunden werden wohl reichen damit die restlichen Paketdaten ankommen, wollt eigentlich noch runtersetzen. Brauch ich das select nicht, damit das recv beim 2. Aufruf nicht blockt, falls keine Daten mehr ankommen, so habe ich das jedenfalls verstanden. 😕



  • _Neuling schrieb:

    Ok mit dem ersten Teil hab ich schon vermutet.

    Vermutet?
    Wie programmierst du denn? "Ich vermute ich bräuchte hier ne Variable... schreiben wir mal eine hin"
    WTF?
    Ist doch vollkommen klar, was gibt es da zu vermuten?

    Ich dachte mir 3 Sekunden werden wohl reichen damit die restlichen Paketdaten ankommen, wollt eigentlich noch runtersetzen. Brauch ich das select nicht, damit das recv beim 2. Aufruf nicht blockt, falls keine Daten mehr ankommen, so habe ich das jedenfalls verstanden. 😕

    Es gibt überhaupt keine Möglichkeit rauszubekommen ob noch was kommt.
    Deswegen legt man die Protokolle auch so aus, dass der Empfänger anhand der Daten rausbekommen kann ob noch was kommt.

    Wenn der Sender auflegt kommt recv() ja sofort zurück.

    Und wenn der Sender einfach aufhört zu senden, oder einfach verschwindet (Kabel ab, Strom weg, ...) ... dann wartet man ewig.



  • Vermutung Driven Development 😉



  • so,select etwas angepasst, ohne Vermutungen diesmal 😃 Die 5Sekunden sind erstmal nur zu Testzwecken(genauso wie einige printf), welche Zeit wäre da realistisch?

    Passt das soweit?

    FD_ZERO(&fd);
    	FD_SET(sock,&fd);
    
        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);
        	size_recv = recv(sock, buffer, sizeof(buffer), 0);
    
        	if (size_recv > 0){
    
        	strcat(data_recv, buffer);
    
        		for(c=0;c<size_recv; c++){
        			if(buffer[c]=='\n'){
        				printf("newline gefunden, raus aus der Schleife\n");
            			printf("Bytes received: %d\n", size_recv);
            			printf("Recv: %s\n", buffer);
                                    return sock;
        			}
        		}
        	}
        else if (size_recv == 0) 
            printf("Connection closed\n"); 
    
        else 
            printf("recv failed: %d\n", WSAGetLastError()); 
    
    	}
    	}while(retselect > 0 );
    
        //printf("Recv: %s\n", buffer);
        printf("data_recv: %s\n",data_recv);
    return sock;
    


  • Das "aneinanderhängen" der Empfangenen Daten ist falsch.
    Deine Einrückung ist inkonsistent und furchtbar.


Log in to reply