CoderBC
CoderBC

Reputation: 1392

How can I pass integer through the buffer?

I want to create a socket that can read some numbers rather than string so that I can perform some manipulations on them. How can I send integer instead of string This is my current program:

  int main(int argc, char *argv[])
{ 
int sockfd, newsockfd, port, clilen;
struct sockaddr_in serv_addr, cli_addr;

if (argc < 2)
error("ERROR, no port provided\n");
port = atoi(argv[1]);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");

bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port); //host to network

if (bind(sockfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR binding to socket");

listen(sockfd,2);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,(struct sockaddr *)&cli_addr, &clilen);
int n;
void* buffer[256];
n = read(newsockfd,buffer,255);


if (n < 0) error("ERROR reading from socket");
printf("Message received:%d\n",d);

n = write(newsockfd,buffer, strlen((char *)buffer));
if (n < 0)
error("ERROR writing back to socket");

return 0;}

I tried this:

int n= 5;
 write(newsockfd,&n, sizeof(int));

But on the client side (also a void* buffer), it doesn't seem to read anything. Can anyone help me how can I rectify this?

One solution could be to pass strings then convert to int etc. But is that the proper way?

Upvotes: 2

Views: 1864

Answers (2)

James K. Lowden
James K. Lowden

Reputation: 7837

I'd like to modify the lucid answer Joachim Pileborg provided.

int value, todo = sizeof(value);
char *p = (void*) &value;

while ( (n = read(newsockfd, p, todo)) < todo ) {
  if( n == 0 ) { /* handle eof and break */ }
  if( n < 0  ) { /* handle error and break */ }

  todo -= n;
  p += n
}

if( todo == 0 ) {
  printf("Received %d\n", value);
}

You know how many bytes you're receiving, so there's no reason to read more. The loop deals with case he warns of: that read(2) may fail to read all 4 bytes (unlikely in this case, but not in general).

You can always get char * from void *, and pass any pointer to a function accepting void *. What you cannot do, portably, is

char buffer[32];
...
int i = *(int *) buffer;

because a character array is not guaranteed to have integer alignment. On some architectures, that provokes SIGBUS. If you read into character array, the safe way to interpret those bytes as an integer is

memcpy(&i, buffer, sizeof i);

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409176

The problem is two-fold:

The first problem is that the declaration void* buffer[256] declares buffer to be an array of 256 pointers to void, not really what's intended I guess. Instead if you want an array of 256 bytes just do char buffer[256].

The second problem is that on the receiving side you treat the data as a string, but it's not a string it's a binary data value.

The second problem can be solved in two ways: Either you convert the integer to a string, and send that string. Or you receive the raw data of the integer, and convert it to an int. The first solution involves sprintf, and the other solution involves either memcpy or pointers and casting.


For the first solution above, you could do something like this:

char temp[32];
snprintf(temp, sizeof temp, "%d", n);
write(newsockfd, temp, sizeof temp);

On the receiving end you read it as a string:

char buffer[32];
n = read(newsockfd, buffer, sizeof buffer);
if (n <= 0)
{
    // Error or connection closed
}

// TODO: Since TCP is a streaming protocol, we could actually receive
//       less than the number of bytes we asked to read, so we need
//       to read in a loop

// Print the received data as a string
printf("Received '%s'\n", buffer);  // Works because the sender sent with the terminator

// Convert to integer
int i = strtol(buffer, NULL, 10);
printf("Received %d\n", i);

For the second solution above, send the integer value as raw binary data as you already do, but when receiving this do something like

char buffer[32];
n = read(newsockfd, buffer, sizeof buffer);
if (n <= 0)
{
    // Error or connection closed
}

// TODO: Since TCP is a streaming protocol, we could actually receive
//       less than the number of bytes we asked to read, so we need
//       to read in a loop

int i = *(int *) buffer;
printf("Received %d\n", i);

Note that this second solution, as it is written in this answer, relies that both the sender and the receiver have the same endianness, as well as the same size for int (which might not always be the case).

The safest way is generally to convert to a string on the sending side, and receive the string as, well, a string. I.e. the first solution.

Upvotes: 3

Related Questions