7

I`m a newbie at programming; I need to send some float values from a program in C++ to another one in C. I found this sample code on the internet and managed to make it works properly:

Server:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

#define MAXLINE 4096 /*max text line length*/
#define SERV_PORT 3000 /*port*/
#define LISTENQ 8 /*maximum number of client connections */

int main (int argc, char **argv)
{
    int listenfd, connfd, n;
    socklen_t clilen;
    char buf[MAXLINE];
    struct sockaddr_in cliaddr, servaddr;

    //creation of the socket
    listenfd = socket (AF_INET, SOCK_STREAM, 0);

    //preparation of the socket address 
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

    listen(listenfd, LISTENQ);

    printf("%s\n","Server running...waiting for connections.");

    for ( ; ; ) {

        clilen = sizeof(cliaddr);
        connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
        printf("%s\n","Received request...");

        while ( (n = recv(connfd, buf, MAXLINE,0)) > 0)  {
            printf("%s","String received from and resent to the client:");
            puts(buf);
            send(connfd, buf, n, 0);
        }

        if (n < 0) {
            perror("Read error"); 
            exit(1);
        }
        close(connfd);

    }
    //close listening socket
    close(listenfd); 

}

Client:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>


#define MAXLINE 4096 /*max text line length*/
#define SERV_PORT 3000 /*port*/

int
main(int argc, char **argv) 
{
    int sockfd;
    struct sockaddr_in servaddr;
    char sendline[MAXLINE], recvline[MAXLINE];

    //basic check of the arguments
    //additional checks can be inserted
    if (argc !=2) {
        perror("Usage: TCPClient <IP address of the server"); 
        exit(1);
    }

    //Create a socket for the client
    //If sockfd<0 there was an error in the creation of the socket
    if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) <0) {
        perror("Problem in creating the socket");
        exit(2);
    }

    //Creation of the socket
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr= inet_addr(argv[1]);
    servaddr.sin_port =  htons(SERV_PORT); //convert to big-endian order

    //Connection of the client to the socket 
    if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0) {
        perror("Problem in connecting to the server");
        exit(3);
    }

    while (fgets(sendline, MAXLINE, stdin) != NULL) {

        send(sockfd, sendline, strlen(sendline), 0);

        if (recv(sockfd, recvline, MAXLINE,0) == 0){
            //error: server terminated prematurely
            perror("The server terminated prematurely"); 
            exit(4);
        }
        printf("%s", "String received from the server: ");
        fputs(recvline, stdout);
    }

    exit(0);
}

So what I have to add to send a float value to server and get it back? The machines are both x86 based, one with Debian 6 installed and the other one with Linux Mint. I tried in both ways (Debian with Client and Linux Mint with Server and Debian with Server and Linux Mint with Client) and it works ok. Im thinking about making some casting between a char value and float... Its that possible? Is there any way to send it without casting? I don`t need a char value, only some float values. Thanks for your help guys!

Edit: I tried with the snprintf and sscanf, but Im doing something wrong because It doesnt works properly. Here are the Client and Server at the moment:

Client:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>


#define MAXLINE 4096 /*max text line length*/
#define SERV_PORT 3000 /*port*/

int
main(int argc, char **argv) 
{
 int sockfd;
 struct sockaddr_in servaddr;
 char sendline[MAXLINE], recvline[MAXLINE], buffer [256];
//Añadidas por mi//
 float a, b, c;
 a = 0;
 b = 0;
 c = 0;
 c = a + b;

  printf("\nPrimer numero: ");
  scanf("%f", &a);
  printf ("\nSegundo numero: ");
  scanf ("%f", &b);

sprintf(buffer, "%f", sizeof c, c);


unsigned char len = strlen(buffer);

 //basic check of the arguments
 //additional checks can be inserted
 if (argc !=2) {
  perror("Usage: TCPClient <IP address of the server");
  exit(1);
 }

 //Create a socket for the client
 //If sockfd<0 there was an error in the creation of the socket
 if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) <0) {
  perror("Problem in creating the socket");
  exit(2);
 }

 //Creation of the socket
 memset(&servaddr, 0, sizeof(servaddr));
 servaddr.sin_family = AF_INET;
 servaddr.sin_addr.s_addr= inet_addr(argv[1]);
 servaddr.sin_port =  htons(SERV_PORT); //convert to big-endian order

 //Connection of the client to the socket 
 if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0) {
  perror("Problem in connecting to the server");
  exit(3);
 }

 while (fgets(sendline, MAXLINE, stdin) != NULL) {

  send(sockfd, sendline, strlen(sendline), 0);
  send(sockfd, &len, sizeof len, 0);
  send (sockfd, buffer, sizeof buffer, 0);

  if (recv(sockfd, recvline, MAXLINE,0) == 0){
   //error: server terminated prematurely
   perror("The server terminated prematurely"); 
   exit(4);
  }
  printf("%s", "String received from the server: ");
  fputs(recvline, stdout);
 }

 exit(0);
}

Server:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

#define MAXLINE 4096 /*max text line length*/
#define SERV_PORT 3000 /*port*/
#define LISTENQ 8 /*maximum number of client connections */

int main (int argc, char **argv)
{
 float c;
 int listenfd, connfd, n;
 socklen_t clilen;
 char buf[MAXLINE], buf256[256], buffer[256];
 unsigned char len = strlen(buffer);
 struct sockaddr_in cliaddr, servaddr;

 //creation of the socket
 listenfd = socket (AF_INET, SOCK_STREAM, 0);

 //preparation of the socket address 
 servaddr.sin_family = AF_INET;
 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 servaddr.sin_port = htons(SERV_PORT);

 bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

 listen(listenfd, LISTENQ);

 printf("%s\n","Server running...waiting for connections.");

 for ( ; ; ) {

  clilen = sizeof(cliaddr);
  connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
  printf("%s\n","Received request...");

  while ( (n = recv(connfd, buf, MAXLINE,0)) > 0)  {
   printf("%s","String received from and resent to the client:");
   puts(buf);


   recv(connfd, &len, sizeof len, 0);
   recv(connfd, buf256, len, 0);
   recv(connfd, buffer, 256, 0);
   buf256[len] = 0;
   sscanf(buffer, "%f", &c);
   puts(buffer);
   printf ("\n%f", &c);   
   send(connfd, buf, n, 0);
  }

 if (n < 0) {
  perror("Read error"); 
  exit(1);
 }
 close(connfd);

 }
 //close listening socket
 close(listenfd); 
}

The programs works weird, it shows values like 0.0000e or sometimes doesnt show nothing. I need to send various float values, so this program its only an example on how to send one float value. Can anybody see where is the error in my program? Thanks!

4
  • 6
    When using the send/recv functions, you must think in terms of buffers, not character arrays. Pass the address of your float variable to send/recv along with the size of your float variable (sizoef(float)). Since you say you are a newbie in programming, I should point out that sending/receiving binary data over a socket has its subtleties such as byte ordering and the width of the individual values. In your case, you will limit yourself to x86 machines and that should work but I recommend to not assume this when developping client/server software. Commented Jul 21, 2016 at 18:23
  • 4
    Convert the float to a string with sprintf, and then convert from a string back to the float with sscanf. Sending a float as raw bits has a number of potential issues: endianness, alignment, encoding (e.g. ieee754), size (usually 4 bytes), ... Commented Jul 21, 2016 at 18:27
  • 4
    @user3386109: Careful: If you want to round-trip floating-point values through decimal representation, you'll need to make sure to fprintf() with sufficient digits (IIRC 9 for float). Probably better to fprintf() as hexadecimal float with "%a". Commented Jul 21, 2016 at 18:50
  • Has Sun's ONC/XDR gone out of fashion? Commented Jul 26, 2016 at 20:35

1 Answer 1

4

Code can send the float using the binary representation. This may work on well matched systems, else may fail due to differing float representation or endian-ness. @clarasoft-it

float x = ...;

// send
send(sockfd, &x, sizeof x, 0);

// receive
recv(connfd, &x, sizeof x, 0);

Alternative code can send the float using a string representation printing with sufficient digits. This is more portable. It does not have an endian-ness issue. It does require conveying string length information. @user3386109 @EOF

If the floating point format differ at the ends, range and precision issues may need additional handling, which is a concern regardless of the method used.

#include <float.h>
#define FLT_EXPO_SIZE 5

// send
// create a buffer large enough
//       -   d   .     ddddd                 e   -       expo       \0
char buf[1 + 1 + 1 + (FLT_DECIMAL_DIG - 1) + 1 + 1 + FLT_EXPO_SIZE + 1];
// print the value to enough digits to distinguish x from all other float
unsigned char len = sprintf(buf, "%.*e", FLT_DECIMAL_DIG - 1, x);
send(sockfd, &len, sizeof len, 0);
send(sockfd, buf, sizeof buf, 0);

// receive
char buf256[256];
recv(connfd, &len, sizeof len, 0);
recv(connfd, buf256, len, 0);
buf256[len] = 0;
sscanf(buf256, "%f", &x);              // add sscanf() check

Notes:

  1. Other code could be used to better define FLT_EXPO_SIZE than the conservative 5. Something based on FLT_MIN_EXP, FLT_MAX_EXP and maybe FLT_TRUE_MIN.

  2. Could use sprintf("%a", x); for a hex representation. TBD buffer size needs in that case. Still can use sscanf(buf, "%f", &x)

  3. Could use snprintf().

  4. Various error checking omitted for brevity.

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for the answers guys, Ill try with the sprintf and sscanf method; Ill post my progress when I try!
Im still having problems sending float values, my program doesnt works properly, anyone can help? I added to the question the code at the moment as I modified it, but it doesnt works properly.
That strlen call is unnecessary because snprintf returns the length but it is ignored.
And send and receive may do partial I/O, so the code must handle such scenarios.
@Joaquin sprintf(buffer, "%f", sizeof c, c); ...printf("\n%f", &c); are invalid code - fully enable your warnings - saves you time.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.