C言語　NTPサーバーより時間を取得

## 時間取得
```
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;
}
```