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: 80173.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 wiechar* blub
) und willst den dann mitstrcat
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, nurstrcat
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 wiestrcat(blub, "")
, undstrcat(blub, "")
hängt einen leeren String an blub an, d.h. macht effektiv nix. Wenn du das Nullbyte mit verschicken willst, dann musst du einfachstrlen(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 1xrecv()
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 keinselect()
vor dem erstenrecv()
? 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.