Reputation: 1392
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
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
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