Linux 网络编程: xinetd time
前言
终于把 xinetd 服务装好了,那就在来实现一下 TCP 协议从服务器和本机获取时间吧。那么多思想汇报还没写,我也是醉了。
安装 xinetd
apt-get install xinetd
配置开启 time 服务
vi /etc/xinetd.d/time
把 disable = yes
改成 disable = no
,看注释很清楚 time 服务返回的是1900年1月1日到现在的秒数。如果没有写的权限,就要 chmod
chmod 777 time
重启 xinetd 服务
service xinetd restart
客户端
errexit.c
/* errexit.c - errexit */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
/*------------------------------------------------------------------------
* errexit - print an error message and exit
*------------------------------------------------------------------------
*/
int errexit(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(1);
}
errno.h
/* Error constants. Linux specific version.
Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifdef _ERRNO_H
# undef EDOM
# undef EILSEQ
# undef ERANGE
# include <linux/errno.h>
/* Linux has no ENOTSUP error code. */
# define ENOTSUP EOPNOTSUPP
/* Linux also had no ECANCELED error code. Since it is not used here
we define it to an invalid value. */
# ifndef ECANCELED
# define ECANCELED 125
# endif
# ifndef __ASSEMBLER__
/* Function to get address of global `errno' variable. */
extern int *__errno_location (void) __THROW __attribute__ ((__const__));
# if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads, errno is a per-thread value. */
# define errno (*__errno_location ())
# endif
# endif /* !__ASSEMBLER__ */
#endif /* _ERRNO_H */
#if !defined _ERRNO_H && defined __need_Emath
/* This is ugly but the kernel header is not clean enough. We must
define only the values EDOM, EILSEQ and ERANGE in case __need_Emath is
defined. */
# define EDOM 33 /* Math argument out of domain of function. */
# define EILSEQ 84 /* Illegal byte sequence. */
# define ERANGE 34 /* Math result not representable. */
#endif /* !_ERRNO_H && __need_Emath */
connectsock.c
/* connectsock.c - connectsock */
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif /* INADDR_NONE */
extern int errno;
int errexit(const char *format, ...);
/*------------------------------------------------------------------------
* connectsock - allocate & connect a socket using TCP or UDP
*------------------------------------------------------------------------
*/
int connectsock(const char *host, const char *service, const char *transport )
/*
* Arguments:
* host - name of host to which connection is desired
* service - service associated with the desired port
* transport - name of transport protocol to use ("tcp" or "udp")
*/
{
struct hostent *phe; /* pointer to host information entry */
struct servent *pse; /* pointer to service information entry */
struct protoent *ppe; /* pointer to protocol information entry*/
struct sockaddr_in sin; /* an Internet endpoint address */
int s, type; /* socket descriptor and socket type */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
/* Map service name to port number */
if ( pse = getservbyname(service, transport) )
sin.sin_port = pse->s_port;
else if ((sin.sin_port=htons((unsigned short)atoi(service))) == 0)
errexit("can't get \"%s\" service entry\n", service);
/* Map host name to IP address, allowing for dotted decimal */
if ( phe = gethostbyname(host) )
memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )
errexit("can't get \"%s\" host entry\n", host);
/* Map transport protocol name to protocol number */
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/* Use protocol to choose a socket type */
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if (s < 0)
errexit("can't create socket: %s\n", strerror(errno));
/* Connect the socket */
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
errexit("can't connect to %s.%s: %s\n", host, service,
strerror(errno));
return s;
}
connectTCP.c
/* connectTCP.c - connectTCP */
int connectsock(const char *host, const char *service,
const char *transport);
/*------------------------------------------------------------------------
* connectTCP - connect to a specified TCP service on a specified host
*------------------------------------------------------------------------
*/
int connectTCP(const char *host, const char *service )
/*
* Arguments:
* host - name of host to which connection is desired
* service - service associated with the desired port
*/
{
return connectsock( host, service, "tcp");
}
TCPtime.c
/* TCPtime.c - TCPtime, main */
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdio.h>
#include <time.h>
extern int errno;
int TCPtime(const char *host, const char *service);
int errexit(const char *format, ...);
int connectTCP(const char *host, const char *service);
#define LINELEN 128
/*------------------------------------------------------------------------
* main - TCP client for DAYTIME service
*------------------------------------------------------------------------
*/
int main(int argc, char *argv[])
{
char *host1 = "localhost"; /* host to use if none supplied */
char *host2 = "localhost"; /* host to use if none supplied */
switch (argc) {
case 1:
host1 = "localhost";
host2 = "localhost";
break;
case 2:
host2 = argv[1];
break;
default:
fprintf(stderr, "The number of parameter is to much! Just need the other host~\n");
exit(1);
}
TCPtime(host1, host2);
exit(0);
}
/*------------------------------------------------------------------------
* TCPtime - invoke Daytime on specified host and print results
*------------------------------------------------------------------------
*/
int TCPtime(const char *host1, const char *host2)
{
char buf[LINELEN+1]; /* buffer for one line of text */
int s1, s2, n; /* socket, read count */
time_t time1, time2;
s1 = connectTCP(host1, "time");
s2 = connectTCP(host2, "time");
while( (n = read(s1, (char *)&time1, sizeof(time1))) > 0) {
time1 = ntohl((unsigned long)time1);
time1 -= 2208988800UL;
time1 += 4294967296UL;
printf("time in %s is %s", host1, ctime(&time1));
}
while( (n = read(s2, (char *)&time2, sizeof(time2))) > 0) {
time2 = ntohl((unsigned long long)time2);
time2 -= 2208988800UL;
time2 += 4294967296UL;
printf("time in %s is %s", host2, ctime(&time2));
}
printf("the difference is %d seconds.\n", abs(time1 - time2));
return 0;
}
time_t 类型的长度在32位机器下是32位,在64位机器下是64位,所以在减去 2208988800UL 秒(变成1970年到现在的秒数)后,还要加上2的32次方秒。(我觉得如果能自己实现64位数的网络序转主机序应该也是可以实现的)。