時間取得
ubuntu@ubuntu:~/kaihatsu/net$ gcc server.c -o server
ubuntu@ubuntu:~/kaihatsu/net$ ./server
現在時刻: 2025-05-22 12:27:11 UTC
ubuntu@ubuntu:~/kaihatsu/net$
Cコード
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
// 定数の定義
#define NTP_SERVER "pool.ntp.org" // NTPサーバーを自動選択
#define NTP_PORT 123 // NTP標準ポート
#define NTP_TIMESTAMP_DELTA 2208988800ULL // 1900年と1970年の時間差(秒数)
/* 詳細計算:
365日/年 × 70年 = 25550日
閏年17日分を追加 = 25550 + 17 = 25567日
25567日 × 86400秒/日 = 2,208,988,800秒
*/
int main() {
// ソケット関連変数
int sockfd; // 通信に使うソケットのID
struct sockaddr_in serv_addr; // サーバー情報格納用
char ntp_packet[48] = {0x1B}; // NTPリクエストデータ
/* NTPパケット先頭バイトの解析:
0b00 (閏秒指示子: 警告なし)
0b011 (バージョン番号: NTPv3)
0b011 (モード: クライアントモード)
バイナリ組み合わせ 00 011 011 → 0x1B
*/
char recv_buffer[48]; // 受信バッファ
struct timeval timeout = {5, 0}; // 5秒受信タイムアウト
// UDPソケットの作成
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("ソケット作成失敗");
exit(EXIT_FAILURE); // 一般的なエラーコードは1
}
// タイムアウト設定(応答がない場合の待機時間)
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
perror("タイムアウト設定失敗");
close(sockfd); // 作成済みソケットを閉じる
exit(EXIT_FAILURE);
}
// サーバー情報設定
memset(&serv_addr, 0, sizeof(serv_addr)); // アドレス構造体をゼロ初期化
serv_addr.sin_family = AF_INET; // IPv4アドレスファミリー
serv_addr.sin_port = htons(NTP_PORT); // ポート番号設定
// ドメイン名→IPアドレス変換
struct hostent *server = gethostbyname(NTP_SERVER);
if (server == NULL) {
fprintf(stderr, "ホスト名解決失敗: %s\n", NTP_SERVER);
close(sockfd);
exit(EXIT_FAILURE);
}
// 解決されたIPアドレスをアドレス構造体に格納
memcpy(&serv_addr.sin_addr, server->h_addr_list[0], server->h_length);
// NTPサーバーにリクエスト送信
if (sendto(sockfd, ntp_packet, sizeof(ntp_packet), 0,
(struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("リクエスト送信失敗");
close(sockfd);
exit(EXIT_FAILURE);
}
// サーバーからの応答受信
socklen_t addr_len = sizeof(serv_addr); // アドレス構造体の長さ
int recv_len = recvfrom(sockfd, recv_buffer, sizeof(recv_buffer), 0,
(struct sockaddr*)&serv_addr, &addr_len);
if (recv_len < 0) {
perror("レスポンス受信失敗");
close(sockfd);
exit(EXIT_FAILURE);
}
// 時刻データ処理
uint32_t ntp_time; // 時刻データ格納用
memcpy(&ntp_time, recv_buffer + 40, 4); // 受信データの40-43バイト目に時刻情報が格納されている
ntp_time = ntohl(ntp_time); // ネットワーク形式→自PC形式に変換(ビッグエンディアン→リトルエンディアンなど)
// NTP時刻(1900年基準)→UNIX時刻(1970年基準)に変換
time_t unix_time = ntp_time - NTP_TIMESTAMP_DELTA;
// 表示する時間形式に変換
struct tm *timeinfo = gmtime(&unix_time); // UTC時間構造体へ変換
char buffer[80];
// 人間が読める形式に変換
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S UTC", timeinfo);
printf("現在時刻: %s\n", buffer);
// ソケットを閉じる
close(sockfd);
return 0;
}