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

前端 未结 4 1761
暖寄归人
暖寄归人 2021-02-20 11:47

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 heada

相关标签:
4条回答
  • 2021-02-20 12:08

    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.

    0 讨论(0)
  • 2021-02-20 12:13

    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.

    0 讨论(0)
  • 2021-02-20 12:27

    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...

    0 讨论(0)
  • 2021-02-20 12:27

    Update: There seems to be a library that provides exactly what you are looking for, check out Apache Portable Runtime, specifically this page on time routines. Other than that, I would say my answer still provides a way to implement this manually, provided all systems are POSIX.1-2001 compliant.

    I'm having a similar problem right now and I think it might be nice to have some instructions on how to go through with this. Note that this solution here should be POSIX.1-2001 compatible (on Ubuntu 14.04, man tzset and man localtime gives such information, and I haven't used other sources, really).

    Use localtime to convert the data obtained from your call to time into a struct tm (see time.h):

    struct tm {
               int tm_sec;         /* seconds */
               int tm_min;         /* minutes */
               int tm_hour;        /* hours */
               int tm_mday;        /* day of the month */
               int tm_mon;         /* month */
               int tm_year;        /* year */
               int tm_wday;        /* day of the week */
               int tm_yday;        /* day in the year */
               int tm_isdst;       /* daylight saving time */
    };
    

    Note that localtime will set the variable declared as (again, see time.h)

    extern long timezone; //seconds West of UTC 
    

    Since all types are now known, you can write your own conversion tool to make this data network-portable. Things to consider:

    • (Preferrably in your software init), you will have to determine how many bytes your int and long have (use sizeof, of course)
    • Based on that information, you could do a host-to-network conversion on each integer field of the struct tm (use htonl or htons - for 64bit types, you will have to write your own) and send that information to the client (in whatever way you like).
      If you have a time zone difference, you will also need to convert/send time zone information, i.e. the data stored in the variable timezone (see above).
    • The client will then have to

      1. Convert the received data into client byte order
      2. Write it into a struct tm (if time zones are involved, write the received time zone data into a long)
      3. If time zones are involved, write the received timezone data into a long and compute the time zone difference (compute the difference of the received timezone datum and what you get by calling tzset locally...), then adjust the struct tm variable created in step 2.
      4. Having obtained a struct tm adjusted to the client's local time zone, use mktime to convert data back into a time_t
      5. Account for time zone difference, if there is any.
    0 讨论(0)
提交回复
热议问题