6

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!

Joaquin
  • 139
  • 1
  • 3
  • 12
  • 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. – clarasoft-it Jul 21 '16 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), ... – user3386109 Jul 21 '16 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"`. – EOF Jul 21 '16 at 18:50
  • Has Sun's ONC/XDR gone out of fashion? – Mark Setchell Jul 26 '16 at 20:35

1 Answers1

3

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.

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Thanks for the answers guys, I`ll try with the sprintf and sscanf method; I`ll post my progress when I try! – Joaquin Jul 22 '16 at 14:05
  • 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. – Joaquin Jul 26 '16 at 17:29
  • 2
    That `strlen` call is unnecessary because `snprintf` returns the length but it is ignored. – Maxim Egorushkin Jul 26 '16 at 17:30
  • 2
    And `send` and `receive` may do partial I/O, so the code must handle such scenarios. – Maxim Egorushkin Jul 26 '16 at 17:31
  • The error should be in the lines I added, the program works fine without them (the first Client - Server I posted).I think the error should be in the Server but Im not sure, maybe something wrong with the recv function? – Joaquin Jul 26 '16 at 17:36
  • @Joaquin 1) "but it doesnt works properly." is vague. Be specific. 2) Unclear why your edited code use `%f` with `*printf()`. Much better to use `%e`. `%f` will print nearly 50% of all different `float` with the value 0.000000 – chux - Reinstate Monica Jul 26 '16 at 18:40
  • @chux It shows anormal values (usually negative ones) or sometimes doesn`t shows nothing. I`ll try what do u say, changing %f for %e and try. – Joaquin Jul 26 '16 at 20:28
  • 1
    @Joaquin `sprintf(buffer, "%f", sizeof c, c); ...printf("\n%f", &c);` are invalid code - fully enable your warnings - saves you time. – chux - Reinstate Monica Jul 26 '16 at 22:01