C - Socket Recv

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb een vraag over sockets in C.

Ik maak verbinding in mijn c app met een socket server die ik in ruby heb geschreven.
Dit ziet er zo uit

C:
1
2
3
4
5
6
7
8
9
10
/* Establish the connection to the echo server */ 
    if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) 
        DieWithError("connect() failed"); 

    /* Socket server handshake */
    echoString = "GET / HTTP/1.1\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\nHost: 192.170.211.209:600\r\nOrigin: http://192.170.211.209\r\n\r\n";
    echoStringLen = strlen(echoString);          /* Determine input length */ 
/* Send the string to the server */ 
    if (send(sock, echoString, echoStringLen, 0) != echoStringLen) 
        DieWithError("send() sent a different number of bytes than expected"); 


Dit gaat helemaal prima en kan ook op de socket server zien dat hij geconnect is.

Vervolgens gaat het systeem een bericht versturen om tegen de andere systemen te vertellen dat hij er is.

C:
1
2
3
4
5
6
7
8
9
10
char  echoString1[255]; // max 255 chars moet genoeg zijn. voor iederee
    strcpy(echoString1, "X000134041113|TX001|TEST33\xff"); 
    echoStringLen1 = strlen(echoString1);          /* Determine input length */ 
    echoString1[0]=0;  /* NULL char on positon 0 */

    /* Send the string to the server */ 
    if (send(sock, echoString1, echoStringLen1, 0) != echoStringLen1) 
        DieWithError("send() sent a different number of bytes than expected"); 

    


Ook dit komt helemaal netjes aan.
Vervolgens wil ik berichten gaan ontvangen die andere clients of deze client krijgt van de server.

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define BUFFER_SIZE  1024

    char buffer[1024];
    int n;
        
    do
    {
        n = recv(sock, buffer, BUFFER_SIZE, 0); /* Receive message from client */
        buffer[n] = '\0'; /* terminate string */
        printf("< %s\n", buffer);
        printf("BSIZE %i\n", BUFFER_SIZE);
        /*send(clientfd, buffer, BUFFER_SIZE, 0);  */

    }
    while(strncmp(buffer, "exit", 4) != 0); /* Exit when client sends "exit" */
 
    close(sock); /*Close socket */
 
    return 0;



En hier is waar het fout gaat. Ik krijg wel het eerste bericht terug dat hij geauthoriseerd is. Maar bij alle andere berichten zie je wel dat het binnenkomt (d.m.v > \n)maar het bericht zelf is niet zichtbaar.

Heeft iemand enig idee wat ik fout doe of wat di tkan zijn?

Alvast bedankt!

Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

recv() kan ook -1 retourneren...

Daarenboven is een TCP connectie stream-oriented in tegenstelling tot UDP wat packet-oriented is. Dat betekent dat je van een TCP connectie moet lezen alsof het een hele lang file is, terwijl je UDP moet lezen als vele kleine files (kort door de bocht toch).

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Dankej wel voor je reactie. Met -1 krijg ik continu legen berichten binnen. Met 0 krijg ik alleen maar lege berichten wanneer er wel daadwerkelijk een bericht verstuurd wordt. Ben een beginner met C, maar dit is het laatste stuk waar ik over struikel van deze app. KAn iemand misschien een voorbeeld geven of helpen wat ik kan doen?

Alvast bedankt

Acties:
  • 0 Henk 'm!

  • leuk_he
  • Registratie: Augustus 2000
  • Laatst online: 15-07 15:35

leuk_he

1. Controleer de kabel!

Bevatten die berichten ook een NULL karakter op de eerste positie? die kun je niet printen met printf. want is die "n" die je uit recv terugkrijgt, want BUFFER_SIZE is je constante, niet het werkelijk aantal ontvangen bytes.

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


Acties:
  • 0 Henk 'm!

  • Onno
  • Registratie: Juni 1999
  • Niet online
Bij het versturen van een bericht begin je met een \0, als de server dat bij z'n reply ook zo doet is het logisch dat printf daar niets van afdrukt. Als je n eens print na het ontvangen van data in plaats van BUFFER_SIZE, is die dan wel groter dan 0?
Verwijderd schreef op zaterdag 12 juni 2010 @ 13:25:
C:
1
2
3
4
5
#define BUFFER_SIZE  1024

char buffer[1024];
n = recv(sock, buffer, BUFFER_SIZE, 0); /* Receive message from client */
buffer[n] = '\0'; /* terminate string */
Dit gaat vroeg of laat tot een buffer overflow leiden.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Dankjewel ;) n is inderdaad groter dan 0 en wordt groter/kleiner naarmate het bericht verstuur groter/kleiner wordt kwa text. dus dat ontvangt hij ook goed. Ik den inderdaad dat de server een \0 mee stuurd. Dus die zou ik er afmoeten slopen op moment dat ik een response krijg? wat is de beste manier hiervoor:)

Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#define BUFFER_SIZE  1024

    char buffer[1024];
    int n;
        
    do
    {
        n = recv(sock, buffer, BUFFER_SIZE, 0); /* Receive message from client */
        if (n < 0)
          break;
        buffer[n == BUFFER_SIZE ? BUFFER_SIZE-1 : n] = '\0'; /* terminate string */
        printf("< %s\n", buffer);
        printf("recv size %i\n", n);
        /*send(clientfd, buffer, BUFFER_SIZE, 0);  */

    }
    while(strncmp(buffer, "exit", 4) != 0); /* Exit when client sends "exit" */
 
    close(sock); /*Close socket */
 
    return 0;

Dit is al een iets opgeschoonde versie.
Die while() conditie is trouwens fout als je TCP gebruikt zoals ik in mijn vorige bericht zei. Als ik je code zie dan vermoed ik dat individuele records/lijnen afgesloten worden met 0xff? In dat geval moet je bufferen en records splitten op 0xff.

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • Onno
  • Registratie: Juni 1999
  • Niet online
H!GHGuY schreef op zaterdag 12 juni 2010 @ 14:08:
C:
1
2
3
4
#define BUFFER_SIZE  1024
char buffer[1024];
n = recv(sock, buffer, BUFFER_SIZE, 0); /* Receive message from client */
buffer[n == BUFFER_SIZE ? BUFFER_SIZE-1 : n] = '\0'; /* terminate string */
Zo sloop je de laatste byte bij n == 1024, dat lijkt me ook niet de bedoeling. Als je dan al per se \0 achter de ontvangen data wilt plakken (maar zoals je al aangeeft wil je eigenlijk eerst bepalen wat een enkele regel / record is) is de enige goede oplossing om je buffer één groter te laten zijn dan de waarde die je aan recv meegeeft.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Dankjewel, dit is inderdaad TCP. Het bericht wordt opdeze manier verstuurd vanaf de server -> "\x00#{data}\xff"

Hoe werkt dat bufferen dan precies? want met de aanpaste code is het resultaat nog wel dat het aantal characters oploopt/afloopt naar mate het bericht dat verstuurd wordt groter of kleiner is, maa rbericht helaas nog niet getoond wordt. misschien een beetje offtopic vraag verder maar bestaat er in C niet zoiets als de print_r in php? Alvast bedankt

Acties:
  • 0 Henk 'm!

  • leuk_he
  • Registratie: Augustus 2000
  • Laatst online: 15-07 15:35

leuk_he

1. Controleer de kabel!

code:
1
2
3
4
5
#define BUFFER_SIZE  1025
char buffer[BUFFER_SIZE];
n = recv(sock, buffer, BUFFER_SIZE-1, 0); /* Receive message from client */
buffer[0]='X' ; /* vervang NULL char op eerste positie zodat printf werkt */
buffer[ n] = '\0'; /*  TODO handle case when n == -1 or SOCKET_ERROR  in case of error */

[ Voor 4% gewijzigd door leuk_he op 12-06-2010 14:54 ]

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


Acties:
  • 0 Henk 'm!

  • Onno
  • Registratie: Juni 1999
  • Niet online
Verwijderd schreef op zaterdag 12 juni 2010 @ 14:22:
Hoe werkt dat bufferen dan precies? want met de aanpaste code is het resultaat nog wel dat het aantal characters oploopt/afloopt naar mate het bericht dat verstuurd wordt groter of kleiner is, maa rbericht helaas nog niet getoond wordt. misschien een beetje offtopic vraag verder maar bestaat er in C niet zoiets als de print_r in php? Alvast bedankt
Wat je meestal doet bij het lezen vanaf een socket is dat je een bepaalde hoeveelheid naar een buffer leest, en daarna op zoek gaat naar het einde van een regel (of record) in (het gevulde gedeelte van) je buffer. Als je die vindt verwerk je je buffer tot dat punt en zoek je daarna verder.

Als je geen volledige regel meer vindt bewaar je de resterende data in je buffer en begin je weer opnieuw met data van je socket te lezen, maar dan niet aan het begin van de buffer maar achter de resterende data aan.

Stel dat je een server bijvoorbeeld de volgende regels verstuurt:

code:
1
2
3
testregel 1\n
testregel 2\n
testregel 3\n


en je client die data naar een buffer van 16 bytes leest. Dan zou je eerste keer dus het volgende kunnen ontvangen:

code:
1
2
testregel 1\n
test


Daarvan verwerk je dan dus de eerste regel, en je bewaart de laatste "test". Enz.
leuk_he schreef op zaterdag 12 juni 2010 @ 14:34:
code:
1
2
3
4
5
#define BUFFER_SIZE  1025
char buffer[1024];
n = recv(sock, buffer, BUFFER_SIZE-1, 0); /* Receive message from client */
buffer[0]='X' ; /* vervang NULL char op eerste positie zodat printf werkt */
buffer[ n] = '\0'; /*  TODO handle case when n == -1 or SOCKET_ERROR  in case of error */
Hiermee is nog steeds dezelfde buffer overflow mogelijk. Daarnaast kun je in het geval dat je zeker weet dat de eerste byte \0 is en daarna nog een string komt beter gewoon &buffer[1] aan printf meegeven, wat je nu doet is een tamelijk lelijke oplossing.

Acties:
  • 0 Henk 'm!

  • leuk_he
  • Registratie: Augustus 2000
  • Laatst online: 15-07 15:35

leuk_he

1. Controleer de kabel!

Onno schreef op zaterdag 12 juni 2010 @ 14:54:

[...]

Hiermee is nog steeds dezelfde buffer overflow mogelijk. Daarnaast kun je in het geval dat je zeker weet dat de eerste byte \0 is en daarna nog een string komt beter gewoon &buffer\[1] aan printf meegeven, wat je nu doet is een tamelijk lelijke oplossing.
Bij lengte 0 van buffer gaat &buffer[1] oplossing weer de mist in. ;) Maar punt is dat topic starter zich effe moet inlezen in C strings

Andere opties is de data niet als strings te beschouwen, maar als buffers van bytes waarbij je de lenge bijhoudt in een 2e (int) variable, en met memcpy de data heen en weer schuift als dat nodig mocht zijn.

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.

Pagina: 1