socket 实现服务端客户端时间同步

2023-10-20 18:05:56 浏览数 (1)

这个小案例主要是演示了服务端客户端通信,时间获取和设定的函数均是从网络上查询的,代码可以顺利编译运行,具体请查看代码和注释。


服务端代码

代码语言:javascript复制
#include <string.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <time.h>
#include “wrap.h”
#define MAXLINE 80
#define SRV_PORT 8000
void datetime(char* _datetime)
{
// 取当前时间到结构体中
time_t t = time(NULL);
struct tm* stime = localtime(&t);
// 格式化时间内容
strftime(_datetime, 20, “%F %H:%M:%S”, stime);
}
int main(int argc, char* argv[])
{
socklen_t cnt_len;
struct sockaddr_in srv_addr, cnt_addr;
int sock, conn;
int n, i;
pid_t pid;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
sock = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&srv_addr, sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
srv_addr.sin_port = htons(SRV_PORT);
Bind(sock, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
Listen(sock, 20);
printf(“Accepting connections …n”);
while (1)
{
cnt_len = sizeof(cnt_addr);
conn = Accept(sock, (struct sockaddr*)&cnt_addr, &cnt_len);
printf(“received from %s at PORT %dn”,
inet_ntop(AF_INET, &cnt_addr.sin_addr, str, sizeof(str)),
ntohs(cnt_addr.sin_port));
pid = fork();
if (pid == 0)
{
Close(sock);
char time[20];
datetime(time);
Write(conn, time, sizeof(time));
Close(conn);
return 0;
}
else if (pid > 0)
{
Close(conn);
}
else
{
perr_exit(“fork”);
}
}
Close(sock);
return 0;
}

客户端代码

代码语言:javascript复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <linux/rtc.h>
#define MAXLINE 80
#define SRV_PORT 8000
int SetSystemTime(char *dt)
{
struct rtc_time tm;
struct tm _tm;
struct timeval tv;
time_t timep;
sscanf(dt, “%d-%d-%d %d:%d:%d”, &tm.tm_year,
&tm.tm_mon, &tm.tm_mday,&tm.tm_hour,
&tm.tm_min, &tm.tm_sec);
_tm.tm_sec = tm.tm_sec;
_tm.tm_min = tm.tm_min;
_tm.tm_hour = tm.tm_hour;
_tm.tm_mday = tm.tm_mday;
_tm.tm_mon = tm.tm_mon - 1;
_tm.tm_year = tm.tm_year - 1900;
timep = mktime(&_tm);
tv.tv_sec = timep;
tv.tv_usec = 0;
if(settimeofday (&tv, (struct timezone *) 0) < 0)
{
printf(“set system datatime error : “);
fflush(stdout);
perror(“”);
return -1;
}
else
{
printf(“set local datetime success : %sn”, dt);
}
return 0;
}
int main(int argc, char* argv[])
{
struct sockaddr_in srv_addr;
int sock, conn;
sock = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&srv_addr, sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
inet_pton(AF_INET, “127.0.0.1”, &srv_addr.sin_addr);
srv_addr.sin_port = htons(SRV_PORT);
int len;
char buf[MAXLINE];
conn = Connect(sock, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
len = Read(sock, buf, sizeof(buf));
if (len != 0)
{
//char time[20];
//strncpy(time, buf, sizeof(time));
SetSystemTime(buf);
}
close(sock);
return 0;
}

公共头文件

代码语言:javascript复制
/* wrap.h */
#ifndef __WRAP_H__
#define __WRAP_H__
void perr_exit(const char* s);
int Accept(int fd, struct sockaddr* sa, socklen_t* salenptr);
void Bind(int fd, const struct sockaddr* sa, socklen_t salen);
void Connect(int fd, const struct sockaddr* sa, socklen_t salen);
void Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void* ptr, size_t nbytes);
ssize_t Write(int fd, const void* ptr, size_t nbytes);
void Close(int fd);
ssize_t Readn(int fd, void* vptr, size_t n);
ssize_t Writen(int fd, const void* vptr, size_t n);
static ssize_t my_read(int fd, char* ptr);
ssize_t Readline(int fd, void* vptr, size_t maxlen);
#endif
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include “wrap.h”
void perr_exit(const char* s)
{
perror(s);
exit(1);
}
int Accept(int fd, struct sockaddr* sa, socklen_t* salenptr)
{
int n;
again:
if ( (n = accept(fd, sa, salenptr)) < 0 )
{
if ((errno == ECONNABORTED)  (errno == EINTR))
{
goto again;
}
else
{
perr_exit(“accept error”);
}
}
return n;
}
void Bind(int fd, const struct sockaddr* sa, socklen_t salen)
{
if ( bind(fd, sa, salen) < 0 )
{
perr_exit(“bind error”);
}
}
void Connect(int fd, const struct sockaddr* sa, socklen_t salen)
{
if ( connect(fd, sa, salen) < 0 )
{
perr_exit(“connect error”);
}
}
void Listen(int fd, int backlog)
{
if ( listen(fd, backlog) < 0 )
{
perr_exit(“listen error”);
}
}
int Socket(int family, int type, int protocol)
{
int n = socket(family, type, protocol);
if ( n < 0 )
{
perr_exit(“socket error”);
}
return n;
}
ssize_t Read(int fd, void* ptr, size_t nbytes)
{
ssize_t n;
again:
if ( (n = read(fd, ptr, nbytes)) == -1)
{
if (errno == EINTR)
{
goto again;
}
else
{
return -1;
}
}
return n;
}
ssize_t Write(int fd, const void* ptr, size_t nbytes)
{
ssize_t n;
again:
if ( (n = write(fd, ptr, nbytes)) == -1)
{
if (errno == EINTR)
{
goto again;
}
else
{
return -1;
}
}
return n;
}
void Close(int fd)
{
if (close(fd) == -1)
{
perr_exit(“close error”);
}
}
ssize_t Readn(int fd, void* vptr, size_t n)
{
size_t nleft;
ssize_t nread;
char* ptr;
ptr = vptr;
nleft = n;
while (nleft > 0)
{
if ( (nread = read(fd, ptr, nleft)) < 0 )
{
if (errno == EINTR)
{
nread = 0;
}
else
{
return -1;
}
}
else if (nread == 0)
{
break;
}
nleft -= nread;
ptr  = nread;
}
}
ssize_t Writen(int fd, const void* vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char* ptr;
ptr = vptr;
nleft = n;
while (nleft > 0)
{
if ( (nwritten = write(fd, ptr, nleft)) <= 0)
{
if (nwritten < 0 && errno == EINTR)
{
nwritten = 0;
}
else
{
return -1;
}
}
nleft -= nwritten;
ptr  = nwritten;
}
return n;
}
static ssize_t my_read(int fd, char* ptr)
{
static int read_cnt;
static char* read_ptr;
static char read_buf[100];
if (read_cnt <= 0)
{
again:
if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0 )
{
if (errno == EINTR)
{
goto again;
}
return -1;
}
else if (read_cnt == 0)
{
return 0;
}
read_ptr = read_buf;
}
read_cnt–;
*ptr = *read_ptr  ;
return 1;
}
ssize_t Readline(int fd, void* vptr, size_t maxlen)
{
ssize_t n, rc;
char c, *ptr;
ptr = vptr;
for (n = 1; n < maxlen; n  )
{
if ( (rc = my_read(fd, &c)) == 1)
{
*ptr   = c;
if (c == ‘n’)
{
break;
}
}
else if (rc == 0)
{
*ptr = 0;
return n - 1;
}
else
{
return -1;
}
*ptr = 0;
return n;
}
}

编译测试代码

编译客户端:gcc time_client.c wrap.c -o time_client 编译服务端:gcc time_server.c wrap.c -o time_server 运行效果(客户端要设定时间需要使用管理员身份运行):

0 人点赞