Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c/c++ - safest way to send time_t over socket

I've set up a C++ server/client environment, and am trying to send a time_t value from the server to the client (an useful thing in any server). But I'm coming accross a headache: time_t seems to not be under any size specifications. I'm wondering what is the safest (more portable) way to send time_t over the network.

This is a little example:

time_t T = time(NULL);
unsigned char * P = (unsigned char *)&T;
// ... Convert it to network byte order, etc.

// Here, 's' would be the socket, and 'S'
// the size of the data that is going to
// be sent
send(s, P, S, 0);

I have two problems:

  • time_t is not size-fixed
  • time_t can be a typedef of a signed or unsigned integral data type

How can I handle that two issues so that I can send it safely between (almost) any architecture?

Thanks in advance.

EDIT: After seeing the same three answers, I find it better to response here. I'm sorry I did not clarify that before. I prefer sending it in 'pure' bytes, although sending it as a string is not a problem. As far as I understand, I would need to keep in mind (again) the signedness and the size of time_t data type in the host system, isn't it? (thanks and sorry)

like image 279
shura-astrozero Avatar asked Dec 19 '12 16:12

shura-astrozero


3 Answers

First, I think you need to decide if you want to deal with the issue that the C standard leaves the meaning of time_t overly vague (it's not necessarily represented in seconds and doesn't even have any meaningful numerical properties like order/comparison). This is contrary to the behavior of every existing and historical implementation, where time_t is in seconds. Both C and POSIX also allow time_t to be a floating point type; as far as I know, no implementations make use of this, and on POSIX it would be rather harmful since the value of time_t has to be an integer the way it's used in struct timespec, etc.

If you decide you're happy assuming time_t is always an integral number of seconds since the epoch, i.e. the values are meaningful for interchange between systems, then it's just a matter of formatting them. The safest thing to do would be to simply cast to a integer type that's large enough to store any meaningful value and that's the same size on all systems: that would be int64_t. Then use whatever normal means you use for serializing int64_t in a way that's immune to endian differences.

If on the other hand you want to be "absolutely" portable, you should compute your own time_t value for "the epoch" (either the standard one or your own choice of epoch), then use difftime to convert to a double representing "seconds since the epoch", and format the double with snprintf(buf, sizeof buf, "%.0f", diff). Note that computing a time_t value for the epoch in portable C is actually quite difficult because most of the standard functions work in local time, whereas you need universal time. There are tricks you can do with the gmtime, mktime, and localtime functions to figure it out, but it's nontrivial...

like image 197
R.. GitHub STOP HELPING ICE Avatar answered Nov 03 '22 18:11

R.. GitHub STOP HELPING ICE


You could send a textual representation produced by strftime in combination with gmtime. The representation would be a bit larger than a binary representation, but not huge. E.g., the format string "%Y%j%H%M%S" produces a 13-byte representation of a moment in time (excluding a NUL character).

EDIT: forget about my previous advice to use ctime; that uses localtime and would therefore only work if client and server are in the same timezone. And apparently, asctime is unsafe, so use strftime.

like image 24
Fred Foo Avatar answered Nov 03 '22 17:11

Fred Foo


You could send it in textual form, with a fixed number of digits. Then you don't have to worry about signs, size incompatibilities, or even byte order.

like image 3
Some programmer dude Avatar answered Nov 03 '22 17:11

Some programmer dude