Reputation: 29
I have the following program (pretty much the example from the GNU manual) that opens a TCP socket, waits for a connection and then prints out the received data byte by byte. Or so I thought...
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 19000
#define MAXMSG 512
int
make_socket (uint16_t port)
{
int sock;
struct sockaddr_in name;
/* Create the socket. */
sock = socket (PF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror ("socket");
exit (EXIT_FAILURE);
}
/* Give the socket a name. */
name.sin_family = AF_INET;
name.sin_port = htons (port);
name.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
{
perror ("bind");
exit (EXIT_FAILURE);
}
return sock;
}
int
read_from_client (int filedes)
{
char buffer[MAXMSG];
int nbytes;
nbytes = read (filedes, buffer, MAXMSG);
if (nbytes < 0)
{
/* Read error. */
perror ("read");
exit (EXIT_FAILURE);
}
else if (nbytes == 0)
/* End-of-file. */
return -1;
else
{
/* Data read. */
fprintf (stderr, "Server: got message:\n");
for (int i = 0; i < nbytes; i++) {
printf(" %02x", buffer[i] & 0xff);
}
printf("\n");
return 0;
}
}
int
main (void)
{
extern int make_socket (uint16_t port);
int sock;
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in clientname;
size_t size;
/* Create the socket and set it up to accept connections. */
sock = make_socket (PORT);
if (listen (sock, 1) < 0)
{
perror ("listen");
exit (EXIT_FAILURE);
}
/* Initialize the set of active sockets. */
FD_ZERO (&active_fd_set);
FD_SET (sock, &active_fd_set);
while (1)
{
/* Block until input arrives on one or more active sockets. */
read_fd_set = active_fd_set;
if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0)
{
perror ("select");
exit (EXIT_FAILURE);
}
/* Service all the sockets with input pending. */
for (i = 0; i < FD_SETSIZE; ++i)
if (FD_ISSET (i, &read_fd_set))
{
if (i == sock)
{
/* Connection request on original socket. */
int new;
size = sizeof (clientname);
new = accept (sock,
(struct sockaddr *) &clientname,
(socklen_t *)&size);
if (new < 0)
{
perror ("accept");
exit (EXIT_FAILURE);
}
fprintf (stderr,
"Server: connect from host %s, port %hd.\n",
inet_ntoa (clientname.sin_addr),
ntohs (clientname.sin_port));
FD_SET (new, &active_fd_set);
}
else
{
/* Data arriving on an already-connected socket. */
if (read_from_client (i) < 0)
{
close (i);
FD_CLR (i, &active_fd_set);
}
}
}
}
}
When I run that and a client connects and sends data it looks like this:
Server: connect from host 10.6.65.167, port -8348.
Server: got message:
ffffffcc ffffffdd ffffffee ffffffff 15 27 00 00 04 13 69 00 ffffff9c 00 00 00 00 00 00 00 ffffffb4 ffffffee ffffffb9 3b 00 00 34 30 36 41 38 45 35 41 45 39 35 31 31 31 31 31 31 50 57 32 41 32 45 30 36 45 2d 47 59 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 61 30 31 39 61 38 64 62 64 34 64 65 35 64 66 61 62 63 31 61 65 30 37 39 33 63 30 32 37 62 38 66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Server: got message:
ffffffcc ffffffdd ffffffee ffffffff 15 27 00 00 04 13 69 00 ffffff9c 00 00 00 00 00 00 00 ffffffb4 ffffffee ffffffb9 3b 00 00 34 30 36 41 38 45 35 41 45 39 35 31 31 31 31 31 31 50 57 32 41 32 45 30 36 45 2d 47 59 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 61 30 31 39 61 38 64 62 64 34 64 65 35 64 66 61 62 63 31 61 65 30 37 39 33 63 30 32 37 62 38 66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...and so on...
Why are there 32 bit long "bytes" in my buffer? How did they even get there? When I look at the network traffic in Wireshark, the first 4 bytes are "cc", "dd", "ee", and "ff", as expected. I'm confused.
Upvotes: 2
Views: 69
Reputation: 2218
everything is ok with your received data.
You have an issue with interpretation of the data in your memory.
I'm sure you are familiar with union concept.
union {
int8_t sb[4];
uint8_t ub[4];
int16_t ss[2];
uint16_t us[2];
float f;
} z;
suppose you fill in this variable from socket stream.
read (d, &z, sizeof(z));
question is : what is in that variable?
answer: whatever you like it to be.
if you need to interpret it as 4 signed bytes then you can address your data as z.sb[0], z.sb[1], z.sb[2], z.sb[3]
it does not matter how you define your buffer when you instruct OS to receive data from network - it is just area of bytes in memory for the network stack.
But it does matter how do you interpret data when you got it from memory. So you could either declare your buffer as:
unsigned char buffer[MAXMSG];
or use pointer to uint8_t to address individual bytes in your buffer.
char buffer[MAXMSG];
uint8_t *b=(uint8_t *)buffer;
for (int i = 0; i < nbytes; i++) {
printf(" %02x", b[i]);
}
Upvotes: 1