Linux下echo与time服务的程序实现

一、针对ECHO服务的TCP客户软件的实现

1.网络拓扑结构:

2.源码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define LINELEN 128
extern int errno;

int TCPecho(const char *host, const char *service);
int errexit(const char *format,…);
int connectsock(const char *host, const char *service, const char *transport );
int connectTCP(const char *host, const char *service);

int main(int argc, char *argv[]){
    char *host= “localhost”;
    char *service= “echo”;
    switch(argc){
case 1:
    host = “localhost”;
    break;
case 3:
    service = argv[2];
case 2:
    host=argv[1];
    break;
default:
    fprintf(stderr,”usage:TCPecho[host[port]]n”);
    exit(1);
    }
    TCPecho(host,service);
    exit(0);
}
int TCPecho(const char *host,const char *service){
    char buf[LINELEN+1];
    int s,n;
    int outchars, inchars;
    s=connectTCP(host, service);
    while(fgets(buf,sizeof(buf),stdin)){
        buf[LINELEN]=’’;
        outchars=strlen(buf);
        (void)write(s,buf,outchars);
        for(inchars=0;inchars            n=read(s,&buf[inchars],outchars-inchars);
            if(n<0)
                    errexit(“socker read failed: %sn”,strerror(errno));
        }
        fputs(buf,stdout);
    }
}
int errexit(const char *format,…){
    va_list arg;
    va_start(arg, format);
    vfprintf(stderr,format,arg);
    va_end(arg);
    exit(1);
}
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 entryn”, 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 entryn”, host);

    /* Map transport protocol name to protocol number */
    if ( (ppe = getprotobyname(transport)) == 0)
        errexit(“can’t get “%s” protocol entryn”, 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: %sn”, strerror(errno));

    /* Connect the socket */
    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        errexit(“can’t connect to %s.%s: %sn”, host, service,
            strerror(errno));
    return s;
}
int connectTCP(const char *host, const char *service){
    return connectsock(host,service,”tcp”);
}

二、针对echo服务的并发的面向连接的服务器软件的实现

1.网络拓扑结构:

2.源码:

#define _USE_BSD
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define QLEN 32
#define BUFSIZE 4096
extern int errno;
unsigned short portbase = 0;

void reaper(int);
int TCPechod(int fd);
int errexit(const char *format,…);
int passivesock(const char *service, const char *transport, int qlen);
int passiveTCP(const char *service,int qlen);

int main(int argc, char *argv[]){
    char *service= “echo”;
    struct sockaddr_in fsin;
    unsigned int alen;
    int msock,ssock;
    switch(argc){
case 1:
    break;
case 2:
    service=argv[1];
    break;
default:
    errexit(“usage: TCPechod [port]n”);
    }

    msock=passiveTCP(service,QLEN);
    (void)signal(SIGCHLD,(__sighandler_t)QLEN);

    while(1){
        alen=sizeof(fsin);
        ssock=accept(msock,(struct sockaddr *)&fsin,&alen);
        if(ssock<0){
            if(errno==EINTR)    continue;
            errexit(“accept: %sn”,strerror(errno));
        }
        switch(fork()){
    case 0:
        (void)close(msock);
        exit(TCPechod(ssock));
    default:
        (void)close(ssock);
        break;
    case -1:
        errexit(“fork: %sn”,strerror(errno));
        }
    }
}

void reaper(int sig){
    int status;
    while(wait3(&status,WNOHANG,(struct rusage *)0)>=0) ;
}
int TCPechod(int fd){
    char buf[BUFSIZ];
    int cc;

    while(cc=read(fd,buf,sizeof(buf))){
        if(cc<0)
            errexit(“echo read: %sn”,strerror(errno));
        if(write(fd,buf,cc)<0)
            errexit(“echo write: %sn”,strerror(errno));
    }
    return 0;
}
int errexit(const char *format,…){
    va_list arg;
    va_start(arg, format);
    vfprintf(stderr,format,arg);
    va_end(arg);
    exit(1);
}
int passivesock(const char *service, const char *transport, int qlen)
/*
 * Arguments:
 *      service  – service associated with the desired port
 *      transport – transport protocol to use (“tcp” or “udp”)
 *      qlen      – maximum server request queue length
 */
{

    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;
    sin.sin_addr.s_addr = INADDR_ANY;

        /* Map service name to port number */
    if ( pse = getservbyname(service, transport) )
    sin.sin_port = htons(ntohs((unsigned short)pse->s_port)+ portbase);
    else
              if ((sin.sin_port=htons((unsigned short)atoi(service)+portbase)) == 0)
    errexit(“can’t create passive service %d n”,sin.sin_port);

        /* Map protocol name to protocol number */
    if ( (ppe = getprotobyname(transport)) == 0)
    errexit(“can’t get “%s” protocol entryn”, 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: %sn”, strerror(errno));

        /* Bind the socket */
    if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    errexit(“can’t bind to %s port: %sn”, service,
    strerror(errno));
    if (type == SOCK_STREAM && listen(s, qlen) < 0)
    errexit(“can’t listen on %s port: %sn”, service,
    strerror(errno));
    return s;
}
int passiveTCP(const char *service,int qlen){
    return passivesock(service,”tcp”,qlen);
}

三、针对TIME服务的UDP客户软件的实现

1.网络拓扑结构:

2.源码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define BUFSIZE 64
#define UNIXEPOCH 2208988800UL
#define MSG “what time is it?n”
extern int errno;

int errexit(const char *format,…);
int connectsock(const char *host, const char *service, const char *transport );
int connectUDP(const char *host, const char *service);

int main(int argc, char *argv[]){
    char *host= “localhost”;
    char *service= “time”;
    time_t now;
    int s,n;

    switch(argc){
case 1:
    host = “localhost”;
    break;
case 3:
    service = argv[2];
case 2:
    host=argv[1];
    break;
default:
    fprintf(stderr,”usage: UDPtime[host[port]]n”);
    exit(1);
    }

    s=connectUDP(host,service);
    (void)write(s,MSG,strlen(MSG));

    n=read(s,(char *)&now,sizeof(now));
    if(n<0)    errexit("read failed: %sn",strerror(errno));
    now=ntohl((unsigned long)now);
    now-=UNIXEPOCH;
    printf(“%s”,ctime(&now));
    exit(0);
}
int errexit(const char *format,…){
    va_list arg;
    va_start(arg, format);
    vfprintf(stderr,format,arg);
    va_end(arg);
    exit(1);
}
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 entryn”, 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 entryn”, host);

    /* Map transport protocol name to protocol number */
    if ( (ppe = getprotobyname(transport)) == 0)
        errexit(“can’t get “%s” protocol entryn”, 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: %sn”, strerror(errno));

    /* Connect the socket */
    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        errexit(“can’t connect to %s.%s: %sn”, host, service,
            strerror(errno));
    return s;
}
int connectUDP(const char *host, const char *service){
    return connectsock(host,service,”udp”);
}

四、针对TIME服务的UDP服务器端软件的实现

1.网络拓扑结构:

2.源码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define UNIXEPOCH 2208988800UL

extern int errno;
unsigned short portbase = 0;

int errexit(const char *format,…);
int passivesock(const char *service, const char *transport, int qlen);
int passiveUDP(const char *service);

int main(int argc, char *argv[]){
    char *service= “time”;
    struct sockaddr_in fsin;
    char buf[1];
    int sock;
    time_t now;
    unsigned int alen;

    switch(argc){
case 1:
    break;
case 2:
    service=argv[1];
    break;
default:
    errexit(“usage: UDPtimed [port]n”);
    }

    sock=passiveUDP(service);

    while(1){
        alen=sizeof(fsin);
        if(recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr *)&fsin,&alen)<0)
            errexit(“recvfrom: %sn”,strerror(errno));
        (void)time(&now);
        now=htonl((unsigned long)(now+UNIXEPOCH));
        (void)sendto(sock,(char*)&now,sizeof(now),0,(struct sockaddr *)&fsin,sizeof(fsin));
    }
}

int errexit(const char *format,…){
    va_list arg;
    va_start(arg, format);
    vfprintf(stderr,format,arg);
    va_end(arg);
    exit(1);
}
int passivesock(const char *service, const char *transport, int qlen)
/*
 * Arguments:
 *      service  – service associated with the desired port
 *      transport – transport protocol to use (“tcp” or “udp”)
 *      qlen      – maximum server request queue length
 */
{

    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;
    sin.sin_addr.s_addr = INADDR_ANY;

        /* Map service name to port number */
    if ( pse = getservbyname(service, transport) )
    sin.sin_port = htons(ntohs((unsigned short)pse->s_port)+ portbase);
    else
              if ((sin.sin_port=htons((unsigned short)atoi(service)+portbase)) == 0)
    errexit(“can’t create passive service %d n”,sin.sin_port);

        /* Map protocol name to protocol number */
    if ( (ppe = getprotobyname(transport)) == 0)
    errexit(“can’t get “%s” protocol entryn”, 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: %sn”, strerror(errno));

        /* Bind the socket */
    if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    errexit(“can’t bind to %s port: %sn”, service,
    strerror(errno));
    if (type == SOCK_STREAM && listen(s, qlen) < 0)
    errexit(“can’t listen on %s port: %sn”, service,
    strerror(errno));
    return s;
}
int passiveUDP(const char *service){
    return passivesock(service,”udp”,0);
}

这里是用的我实验时的代码,前两个是关于echo服务的客户端与服务器端,有下面运行截图:

后两个是关于time服务的,有下面运行截图:

实验时由于多次运行验证,总会出现端口占用的情况,于是这里每次运行时都输入程序的入口参数(就是main函数里的形参),自选端口,方便至极。还有就是代码里多个函数可以写入多个cpp里,这里偷懒了。