В общем случае отправка двоичных данных подвержена ошибкам из-за возможности различных способов их интерпретации на стороне отправителя и получателя.
В частности, для time_t
даже неясно, сколько битов будет задействовано, это может быть 32 или 64 или даже что-то гораздо более сложное, поскольку time_t
может даже быть реализовано как struct
.
В вашем особом случае с использованием htonl()
предполагается 32 бита, как htonl()
принимает 32-битное значение.
Таким образом, надежное решение действительно состоит в том, чтобы отправить текстовое представление системного времени.
Программно это может выглядеть так:
char st[64] = "";
{
struct * tm = gmtime(time(NULL));
if (NULL == tm)
{
fprintf(stderr, "gmtime() failed\n");
}
{
if(0 == strftime(st, sizeof(st), "%s", tm)) /* Prints the text representaiotn of the seconds since Epoch into st. */
{
fprintf(stderr, "strftime() failed\n");
}
}
}
Чтобы отменить эту операцию, вы можете использовать strptime()
:
char st[64] = "123456789123";
time_t t;
memset(&t, 0, sizeof(t));
{
struct tm = {0};
char p = strptime(t, "%s", &tm);
if (NULL == p || p != (t + strlen(t)))
{
fprintf(stderr, "strptime() failed\n");
}
else
{
t = mktime(&tm);
}
}
Преимущество использования strptime()
и strftime()
заключается в том, что вы можете легко изменить формат даты/времени в пути, просто изменив формат, указанный при вызове этих двух функций.
Изменение "%s"
на "%Y-%m-%d %H:%M:%S"
перенесет время как "2014-05-20 13:14:15"
.
Однако, если вы действительно хотите отправлять секунды с начала эпохи в двоичном формате и оставаться безотказным и переносимым, вам нужно позаботиться о трех вещах:
- Получите количество секунд с начала эпохи портативным способом.
- Выберите целочисленный тип определенно достаточно большим.
- Преобразуйте это «большое» значение в сетевой порядок байтов.
Возможный подход для этого:
#include <time.h>
#include <inttypes.h> /* For uint64_t, as 64bit should do to represent the seconds since Epoch for the next few years. */
...
time_t t_epochbegin;
memset(&t_epochbegin, 0, sizeof(t_epochbegin);
uint64_t t_host = (uint64_t) difftime(time(NULL), t_epochbegin); /* Get the seconds since Epoch without relying on time_t being an integer. */
uint64_t t_network = htonll(t_host); /* Convert to network byte order. */
О том, как реализовать нестандартный htonll()
, см. различные ответы на этот вопрос: поддержка Big Endian и Little Endian для порядка байтов
Весь код в приведенных выше примерах предполагает, что система, в которой выполняется код, предоставляет таймер, и хотя вызовы time()
не завершатся ошибкой.
person
alk
schedule
26.06.2014