使用方式
ntp_server ntp1.aliyun.com
目录结构
ntp_server/
Android.mk
long2time.cpp
long2time.h
main.cpp
ntp_server.rc
Android.mk文件内容
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE = ntp_server
LOCAL_SRC_FILES = long2time.cpp \
main.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_INIT_RC := ntp_server.rc
LOCAL_CFLAGS += -Wall -Wno-unused-parameter
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
libandroidfw \
libutils
include $(BUILD_EXECUTABLE)
long2time.cpp文件内容
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <cutils/properties.h>
#include "long2time.h"
#define UTC_BASE_YEAR 1970
#define MONTH_PER_YEAR 12
#define DAY_PER_YEAR 365
#define SEC_PER_DAY 86400
#define SEC_PER_HOUR 3600
#define SEC_PER_MIN 60
/* 每个月的天数 */
const unsigned char g_day_per_mon[MONTH_PER_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/*
* 功能:
* 判断是否是闰年
* 参数:
* year:需要判断的年份数
*
* 返回值:
* 闰年返回1,否则返回0
*/
unsigned char applib_dt_is_leap_year(unsigned short year)
{
if ((year % 400) == 0)
{
return 1;
}
else if ((year % 100) == 0)
{
return 0;
}
else if ((year % 4) == 0)
{
return 1;
}
else
{
return 0;
}
}
/*
* 功能:
* 得到每个月有多少天
* 参数:
* month:需要得到天数的月份数
* year:该月所对应的年份数
*
* 返回值:
* 该月有多少天
*
*/
unsigned char applib_dt_last_day_of_mon(unsigned char month, unsigned short year)
{
if ((month == 0) || (month > 12))
{
return g_day_per_mon[1] + applib_dt_is_leap_year(year);
}
if (month != 2)
{
return g_day_per_mon[month - 1];
}
else
{
return g_day_per_mon[1] + applib_dt_is_leap_year(year);
}
}
long getRtcTime()
{
int fd, size;
char buffer[50];
int hour, minunte, second;
long time;
fd = open("/sys/class/rtc/rtc0/time", O_RDONLY);
if (fd < 0)
{
INFO("open /sys/class/rtc/rtc0/time failed");
}
size = read(fd, buffer, sizeof(buffer));
close(fd);
sscanf(buffer, "%d:%d:%d", &hour, &minunte, &second);
time = hour * 3600 + minunte * 60 + second;
//INFO("hour = %d minunte = %d second = %d time = %ld",hour,minunte,second,time);
return time;
}
int setRtcTime(long millis)
{
char time[25], rtcTime[25];
sprintf(time, "%ld", millis);
property_set("persist.sys.time", time);
long rtcSettings = getRtcTime();
sprintf(rtcTime, "%ld", rtcSettings);
property_set("persist.sys.settingsrtc", rtcTime);
return 0;
}
void change(long ts)
{
int year = 0;
int month = 0;
int day = 0;
int hour = 0;
int minute = 0;
int second = 0;
char str[80];
//将时间戳值转化成天数。通过天数可以比较方便地算出年、月、日。
int days = ts / SEC_PER_DAY;
//这个时间戳值的年。
int yearTmp = 0;
int dayTmp = 0;
//使用夹逼法计算 days 天中包含的年数。
for (yearTmp = UTC_BASE_YEAR; days > 0; yearTmp++)
{
dayTmp = (DAY_PER_YEAR + applib_dt_is_leap_year(yearTmp)); //这一年有多少天?
if (days >= dayTmp) //条件成立,则 yearTmp 即是这个时间戳值所代表的年数。
{
days -= dayTmp;
}
else
{
break;
}
}
year = yearTmp;
//这个时间戳值的月
int monthTmp = 0;
for (monthTmp = 1; monthTmp < MONTH_PER_YEAR; monthTmp++)
{
dayTmp = applib_dt_last_day_of_mon(monthTmp, year);
if (days >= dayTmp)
{
days -= dayTmp;
}
else
{
break;
}
}
month = monthTmp;
day = days + 1;
//转化成秒。
int secs = ts % SEC_PER_DAY;
//这个时间戳值的小时数。
hour = secs / SEC_PER_HOUR;
//这个时间戳值的分钟数。
secs %= SEC_PER_HOUR;
minute = secs / SEC_PER_MIN;
//这个时间戳的秒钟数。
second = secs % SEC_PER_MIN;
sprintf(str, "date %d%d%d%d%d.%d set", month, day, hour, minute, year, second);
if (system(str) < 0)
{
printf("cmd : %s\t error\n", str);
}
// if (system("busybox hwclock -w") < 0) {
// printf("cmd : busybox hwclock -w\t error\n");
// }
}
long2time.h文件内容
#ifndef LONG2TIME_H
#define LONG2TIME_H
#include <utils/Log.h>
#define TAG "vclusters"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define debugprintf 1
#ifdef debugprintf
#define debugpri(mesg, args...) fprintf(stderr, "[NetRate print:%s:%d:] " mesg "\n", __FILE__, __LINE__, ##args)
#else
#define debugpri(mesg, args...)
#endif
#define INFO(...) \
do \
{ \
printf(__VA_ARGS__); \
printf("\n"); \
LOGI(__VA_ARGS__); \
} while (0)
const char DEFAULT_NTP_SERVER[16] = "ntp1.aliyun.com";
unsigned char applib_dt_is_leap_year(unsigned short year);
unsigned char applib_dt_last_day_of_mon(unsigned char month, unsigned short year);
void change(long ts);
long getRtcTime();
int setRtcTime(long millis);
#endif
ntp_server.rc内容
service ntp_server /system/bin/ntp_server start
class late_start
user root
disabled
oneshot
on property:sys.boot_completed=1
start ntp_server
main.cpp内容
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <dirent.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/properties.h>
#include "long2time.h"
#define JAN_1970 0x83aa7e80
#define NTPFRAC(x) (4294 * (x) + ((1981 * (x)) >> 11))
#define USEC(x) (((x) >> 12) - 759 * ((((x) >> 10) + 32768) >> 16))
#define Data(i) ntohl(((unsigned int *)data)[i])
#define LI 0
#define VN 3
#define MODE 3
#define STRATUM 0
#define POLL 4
#define PREC -6
struct NtpTime
{
unsigned int coarse;
unsigned int fine;
};
void sendPacket(int fd)
{
unsigned int data[12];
struct timeval now;
if (sizeof(data) != 48)
{
fprintf(stderr, "size error\n");
return;
}
memset((char *)data, 0, sizeof(data));
data[0] = htonl((LI << 30) | (VN << 27) | (MODE << 24) | (STRATUM << 16) | (POLL << 8) | (PREC & 0xff)); //构造协议头部信息
data[1] = htonl(1 << 16);
data[2] = htonl(1 << 16);
gettimeofday(&now, NULL);
data[10] = htonl(now.tv_sec + JAN_1970); //构造传输时间戳
data[11] = htonl(NTPFRAC(now.tv_usec));
send(fd, data, 48, 0);
}
//获取NTP服务器返回的时间
void getNewTime(unsigned int *data, struct timeval *ptimeval)
{
struct NtpTime trantime;
trantime.coarse = Data(10);
trantime.fine = Data(11);
ptimeval->tv_sec = trantime.coarse - JAN_1970;
ptimeval->tv_usec = USEC(trantime.fine);
}
int getNtpTime(struct hostent *phost, struct timeval *ptimeval)
{
if (phost == NULL)
{
debugpri("err:host is null!\n");
return -1;
}
int sockfd;
struct sockaddr_in addr_src, addr_dst;
fd_set fds;
int ret;
int recv_len;
unsigned int buf[12];
memset(buf, 0, sizeof(buf));
int addr_len;
int count = 0;
struct timeval timeout;
addr_len = sizeof(struct sockaddr_in);
memset(&addr_src, 0, addr_len);
addr_src.sin_family = AF_INET;
addr_src.sin_addr.s_addr = htonl(INADDR_ANY);
addr_src.sin_port = htons(0);
memset(&addr_dst, 0, addr_len);
addr_dst.sin_family = AF_INET;
memcpy(&(addr_dst.sin_addr.s_addr), phost->h_addr_list[0], 4);
addr_dst.sin_port = htons(123); //ntp默认端口123
if (-1 == (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))) //创建UDP socket
{
debugpri("create socket error!\n");
return -1;
}
ret = bind(sockfd, (struct sockaddr *)&addr_src, addr_len); //bind
if (-1 == ret)
{
debugpri("bind error!\n");
close(sockfd);
return -1;
}
ret = connect(sockfd, (struct sockaddr *)&addr_dst, addr_len); //连接NTP服务器
if (-1 == ret)
{
debugpri("connect error!\n");
close(sockfd);
return -1;
}
sendPacket(sockfd); //发送请求包
while (count < 50) //轮询请求
{
FD_ZERO(&fds);
FD_SET(sockfd, &fds);
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
ret = select(sockfd + 1, &fds, NULL, NULL, &timeout);
if (0 == ret)
{
count++;
debugpri("ret == 0\n");
sendPacket(sockfd);
usleep(100 * 1000);
continue;
}
if (FD_ISSET(sockfd, &fds))
{
recv_len = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr_dst, (socklen_t *)&addr_len);
if (-1 == recv_len)
{
debugpri("recvfrom error\n");
close(sockfd);
return -1;
}
else if (recv_len > 0)
{
debugpri("receiv data\n");
getNewTime(buf, ptimeval);
debugpri("sec = %ld usec = %ld", ptimeval->tv_sec, ptimeval->tv_usec); //打印输出NTP服务器返回的时间
change(ptimeval->tv_sec + 8 * 3600);
setRtcTime(ptimeval->tv_sec * 1000);
break;
}
}
else
{
debugpri("count %d \n", count);
usleep(50 * 1000);
count++;
}
}
if (count >= 50)
{
debugpri("getNewTime timeout fail \n");
close(sockfd);
return -1;
}
close(sockfd);
return 0;
}
int main(int argc, char **argv)
{
char noethernet[PROPERTY_VALUE_MAX];
property_get("persist.ruichi.native_agent", noethernet, NULL);
if (strcmp("1", noethernet) != 0)
{
INFO("persist.ruichi.native_agent = 0");
return 0;
}
struct timeval TimeSet;
static struct hostent *host = NULL;
char ntpServer[PROPERTY_VALUE_MAX];
char CrtcLastTime[PROPERTY_VALUE_MAX];
char CsettingTime[PROPERTY_VALUE_MAX];
long rtcNowTime;
long currentTime;
long settingTime;
long rtcLastTime;
INFO("vclusters argc = %d argv[1] = %s\n", argc, argv[1]);
if (argc == 2)
{
if (strcmp("start", argv[1]) == 0)
{
property_get("persist.sys.settingsrtc", CrtcLastTime, NULL);
property_get("persist.sys.time", CsettingTime, NULL);
settingTime = atol(CsettingTime);
rtcLastTime = atol(CrtcLastTime);
rtcNowTime = getRtcTime();
currentTime = settingTime + (rtcNowTime - rtcLastTime) * 1000;
INFO("settingTime = %ld rtcNowTime = %ld rtcLastTime = %ld currentTime = %ld", settingTime, rtcNowTime, rtcLastTime, currentTime);
change(currentTime / 1000 + 8 * 3600);
sleep(10);
property_get("persist.ruichi.ntpServer", ntpServer, DEFAULT_NTP_SERVER);
host = gethostbyname(ntpServer);
//INFO("persist.ruichi.ntpServer = %s",ntpServer);
}
else
{
host = gethostbyname(argv[1]);
property_set("persist.ruichi.ntpServer", argv[1]);
}
memset(&TimeSet, 0, sizeof(TimeSet));
getNtpTime(host, &TimeSet);
}
return 0;
}
github 源码
gitclone [email protected]:hejiangzhou1/ntp_server.git
参考博客: