xinetd 服务器 return 值不可读
xinetd server return value is not readable
我已经启用了所有 xinetd 服务,并且我正在从 c 程序调用它。一切正常,但当我调用时间服务时,它 returns 4 字节值不可读。以下是一个示例输出。
那么,如何将此输出转换为可读格式?
根据Wikipedia:
The server then sends the time as a 32-bit unsigned integer in binary format and in network byte order, representing the number of seconds since 00:00 (midnight) 1 January, 1900 GMT, and closes the connection.
解码为本机字节顺序(通过 ntohl()
或朋友)后,您可以对该值做任何您喜欢的事情。请注意,它不会像 ctime()
这样的 time_t
函数按原样工作,因为正常的 Unix 纪元(0 点)是不同的日期。幸运的是,这可以通过从提供的时间中减去时间协议的 0 点的纪元偏移量来解决。
这是一个示例程序,它连接到作为其唯一命令行参数传递的给定 IP 地址或主机名的时间服务,并打印出接收到的值和人类可读的日期字符串(使用上述偏移量来转换为正常的 Unix 时间值):
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
// 00:00 1 Jan 1970 GMT in RFC 868 time format.
#define EPOCH_OFFSET 2208988800U
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s hostname\n", argv[0]);
return EXIT_FAILURE;
}
struct addrinfo *res;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM
};
int err;
if ((err = getaddrinfo(argv[1], "time", &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
return EXIT_FAILURE;
}
for (struct addrinfo *addr = res; addr; addr = addr->ai_next) {
int s = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (s >= 0) {
if (connect(s, addr->ai_addr, addr->ai_addrlen) == 0) {
uint32_t raw;
if (read(s, &raw, sizeof raw) != sizeof raw) {
fprintf(stderr, "Could not read complete time.\n");
close(s);
freeaddrinfo(res);
return EXIT_FAILURE;
}
raw = ntohl(raw);
printf("Got raw time: %" PRIu32 "\n", raw);
time_t tval = raw - EPOCH_OFFSET;
printf("Converted time: %s", ctime(&tval));
close(s);
freeaddrinfo(res);
return 0;
} else {
close(s);
}
}
}
printf("Unable to connect to %s's time server.\n", argv[1]);
freeaddrinfo(res);
return EXIT_FAILURE;
}
我已经启用了所有 xinetd 服务,并且我正在从 c 程序调用它。一切正常,但当我调用时间服务时,它 returns 4 字节值不可读。以下是一个示例输出。
那么,如何将此输出转换为可读格式?
根据Wikipedia:
The server then sends the time as a 32-bit unsigned integer in binary format and in network byte order, representing the number of seconds since 00:00 (midnight) 1 January, 1900 GMT, and closes the connection.
解码为本机字节顺序(通过 ntohl()
或朋友)后,您可以对该值做任何您喜欢的事情。请注意,它不会像 ctime()
这样的 time_t
函数按原样工作,因为正常的 Unix 纪元(0 点)是不同的日期。幸运的是,这可以通过从提供的时间中减去时间协议的 0 点的纪元偏移量来解决。
这是一个示例程序,它连接到作为其唯一命令行参数传递的给定 IP 地址或主机名的时间服务,并打印出接收到的值和人类可读的日期字符串(使用上述偏移量来转换为正常的 Unix 时间值):
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
// 00:00 1 Jan 1970 GMT in RFC 868 time format.
#define EPOCH_OFFSET 2208988800U
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s hostname\n", argv[0]);
return EXIT_FAILURE;
}
struct addrinfo *res;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM
};
int err;
if ((err = getaddrinfo(argv[1], "time", &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
return EXIT_FAILURE;
}
for (struct addrinfo *addr = res; addr; addr = addr->ai_next) {
int s = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (s >= 0) {
if (connect(s, addr->ai_addr, addr->ai_addrlen) == 0) {
uint32_t raw;
if (read(s, &raw, sizeof raw) != sizeof raw) {
fprintf(stderr, "Could not read complete time.\n");
close(s);
freeaddrinfo(res);
return EXIT_FAILURE;
}
raw = ntohl(raw);
printf("Got raw time: %" PRIu32 "\n", raw);
time_t tval = raw - EPOCH_OFFSET;
printf("Converted time: %s", ctime(&tval));
close(s);
freeaddrinfo(res);
return 0;
} else {
close(s);
}
}
}
printf("Unable to connect to %s's time server.\n", argv[1]);
freeaddrinfo(res);
return EXIT_FAILURE;
}