Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending float values on socket C/C++

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!

like image 595
Joaquin Avatar asked Jul 21 '16 18:07

Joaquin


1 Answers

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.

like image 109
chux - Reinstate Monica Avatar answered Oct 28 '22 18:10

chux - Reinstate Monica