用TCP/TP进行网际互连(7) ———— 支持多协议多服务的服务器设计和实现

来源:互联网 发布:足球数据app 编辑:程序博客网 时间:2024/05/20 00:36

用TCP/TP进行网际互连(7)

———— 支持多协议多服务的服务器设计和实现

融合之前实现的各种协议与服务的代码,实现一个支持多协议多服务的服务器。

1、实现过程

  • 服务器:
    这里写图片描述
    • errexit.c、passivesock.c、passiveTCP.c、passiveUDP.c分别是之前对相应过程代码的封装。
    • superd.c :在初始化数据结构并为它所提供的每个服务打开套接字之后,服务器主程序便进入了无限循环。每一次循环都调用select,以便等待各套接字中的某个准备就绪。当请求到达时,select就返回。
    • sv_funcs.c :是一些提供的服务的具体实现,包含TCPechod(int), TCPchargend(int), TCPdaytimed(int), TCPtimed(int), UDPechod(int), UDPtimed(int);

这里只贴一下主要代码,全部代码已上传github,有兴趣可以拿来看一下:
https://github.com/KevinBetterQ/Network-programming/tree/master/All/S

//superd.c :int main(int argc, char *argv[]){    struct service  *psv,       /* service table pointer    */        *fd2sv[NOFILE];     /* map fd to service pointer    */    int fd, nfds;    fd_set  afds, rfds;     /* readable file descriptors    */    switch (argc) {    case 1:        break;    case 2:        portbase = (unsigned short) atoi(argv[1]);        break;    default:        errexit("usage: superd [portbase]\n");    }    nfds = 0;    FD_ZERO(&afds);    for (psv = &svent[0]; psv->sv_name; ++psv) {        if (psv->sv_useTCP)            psv->sv_sock = passiveTCP(psv->sv_name, QLEN);        else            psv->sv_sock = passiveUDP(psv->sv_name);        fd2sv[psv->sv_sock] = psv;        nfds = MAX(psv->sv_sock+1, nfds);        FD_SET(psv->sv_sock, &afds);    }    (void) signal(SIGCHLD, reaper);    while (1) {        memcpy(&rfds, &afds, sizeof(rfds));        if (select(nfds, &rfds, (fd_set *)0, (fd_set *)0,                (struct timeval *)0) < 0) {            if (errno == EINTR)                continue;            errexit("select error: %s\n", strerror(errno));        }        for (fd=0; fd<nfds; ++fd)            if (FD_ISSET(fd, &rfds)) {                psv = fd2sv[fd];                if (psv->sv_useTCP)                    doTCP(psv);                else                    psv->sv_func(psv->sv_sock);            }    }}/*------------------------------------------------------------------------ * doTCP - handle a TCP service connection request *------------------------------------------------------------------------ */voiddoTCP(struct service *psv){    struct sockaddr_in fsin;    /* the request from address */    unsigned int    alen;       /* from-address length      */    int fd, ssock;    alen = sizeof(fsin);    ssock = accept(psv->sv_sock, (struct sockaddr *)&fsin, &alen);    if (ssock < 0)        errexit("accept: %s\n", strerror(errno));    switch (fork()) {    case 0:         break;    case -1:        errexit("fork: %s\n", strerror(errno));    default:        (void) close(ssock);        return;     /* parent */    }    /* child */    for (fd = NOFILE; fd >= 0; --fd)        if (fd != ssock)            (void) close(fd);    psv->sv_func(ssock);    exit(0);}
//sv_funcs.c:void  TCPechod(int fd){    char    buf[BUFFERSIZE];    int cc;    while (cc = read(fd, buf, sizeof buf)) {        if (cc < 0)            errexit("echo read: %s\n", strerror(errno));        if (write(fd, buf, cc) < 0)            errexit("echo write: %s\n", strerror(errno));    }}voidUDPechod(int sock){    struct sockaddr_in fsin;    /* the from address of a client */    char    buf[128];           /* "input" buffer; any size > 0 */    time_t  now;            /* current time         */    unsigned int    alen;       /* from-address length      */    int n;                                              /*接收数据长度*/        alen = sizeof(fsin);        n = recvfrom(sock, buf, sizeof(buf), 0,                (struct sockaddr *)&fsin, &alen);           (void) sendto(sock, buf, n, 0,            (struct sockaddr *)&fsin, sizeof(fsin));}/*------------------------------------------------------------------------ * TCPdaytimed - do TCP DAYTIME protocol *------------------------------------------------------------------------ */voidTCPdaytimed(int fd){    char    buf[LINELEN], *ctime();    time_t  now;    (void) time(&now);    sprintf(buf, "%s", ctime(&now));    (void) write(fd, buf, strlen(buf));}#define UNIXEPOCH   2208988800UL    /* UNIX epoch, in UCT secs  */voidTCPtimed(int fd){    time_t  now;    (void) time(&now);    now = htonl((unsigned long)(now + UNIXEPOCH));    (void) write(fd, (char *)&now, sizeof(now));}voidUDPtimed(int sock){    struct sockaddr_in fsin;    /* the from address of a client */    char    buf[1];         /* "input" buffer; any size > 0 */    time_t  now;            /* current time         */    unsigned int    alen;       /* from-address length      */        alen = sizeof(fsin);        if (recvfrom(sock, buf, sizeof(buf), 0,                (struct sockaddr *)&fsin, &alen) < 0)            errexit("recvfrom: %s\n", strerror(errno));        (void) time(&now);        now = htonl((unsigned long)(now + UNIXEPOCH));        (void) sendto(sock, (char *)&now, sizeof(now), 0,            (struct sockaddr *)&fsin, sizeof(fsin));}
  • 客户端
    这里写图片描述
    • connectsock.c、connectTCP.c、connectUDP.c、errexit.c分别是之前对相应过程代码的封装。
    • TCPdaytime.c、TCPecho.c、UDPecho.c、UDPtime.c分别对象文件名的相应协议与服务。

下面也只放一下主要功能代码部分,全部代码可以参考:
https://github.com/KevinBetterQ/Network-programming/tree/master/All/C

//TCPdaytime.c/*------------------------------------------------------------------------ * TCPdaytime - invoke Daytime on specified host and print results *------------------------------------------------------------------------ */TCPdaytime(const char *host, const char *service){    char    buf[LINELEN+1];     /* buffer for one line of text  */    int s, n;           /* socket, read count       */    s = connectTCP(host, service);    while( (n = read(s, buf, LINELEN)) > 0) {        buf[n] = '\0';      /* ensure null-terminated   */        (void) fputs( buf, stdout );    }}
//TCPecho.cint TCPecho(const char *host, const char *service){    char    buf[LINELEN+1];     /* buffer for one line of text  */    int s, n;           /* socket descriptor, read count*/    int outchars, inchars;  /* characters sent and received */    s = connectTCP(host, service);    while (fgets(buf, sizeof(buf), stdin)) {        buf[LINELEN] = '\0';    /* insure line null-terminated  */        outchars = strlen(buf);        (void) write(s, buf, outchars);        /* read it back */        for (inchars = 0; inchars < outchars; inchars+=n ) {            n = read(s, &buf[inchars], outchars - inchars);            if (n < 0)                errexit("socket read failed: %s\n",                    strerror(errno));        }        fputs(buf, stdout);    }}
//UDPecho.cint UDPecho(const char *host, const char *service){    char    buf[LINELEN+1];     /* buffer for one line of text  */    int s, nchars;      /* socket descriptor, read count*/    s = connectUDP(host, service);    while (fgets(buf, sizeof(buf), stdin)) {        buf[LINELEN] = '\0';    /* insure null-terminated */        nchars = strlen(buf);        (void) write(s, buf, nchars);        if (read(s, buf, nchars) < 0)            errexit("socket read failed: %s\n",                    strerror(errno));        fputs(buf, stdout);    }}
//UDPtime.cint main(int argc, char *argv[]){    char    *host = "localhost";    /* host to use if none supplied */    char    *service = "time";  /* default service name     */    time_t  now;            /* 32-bit integer to hold time  */     int s, n;           /* socket descriptor, read count*/    switch (argc) {    case 1:        host = "localhost";        break;    case 3:        service = argv[2];        /* FALL THROUGH */    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));    /* Read the time */    n = read(s, (char *)&now, sizeof(now));    if (n < 0)        errexit("read failed: %s\n", strerror(errno));    now = ntohl((unsigned long)now);    /* put in host order    */    now -= UNIXEPOCH;       /* convert UCT to UNIX epoch    */    printf("%s", ctime(&now));    exit(0);}

2、效果展示

  • 开启服务器::
    这里写图片描述

  • 客户端连接:
    这里写图片描述

    可以看到两种协议的四个服务都可以实现了。

阅读全文
1 0
原创粉丝点击