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位数的网络序转主机序应该也是可以实现的)。

编译运行

posted @ 2015-10-27 15:27  百學須先立志  阅读(331)  评论(0编辑  收藏  举报