Joaquin Joaquin - 4 months ago 15
Linux Question

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.
I
m thinking about making some casting between a char value and float... It
s 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!

Answer

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
sprintf(buf, "%.*e", FLT_DECIMAL_DIG - 1, x);
unsigned char len = strlen(buf);
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.