网络程序设计——6.支持多协议多服务的服务器设计和实现

本文详细介绍了如何设计和实现一个多协议多服务的服务器,包括TCP和UDP服务的处理,如TCP回显、UDP时间服务等。文章提供了完整的源代码示例,包括服务器端和客户端的代码,并给出了Makefile的编写规则。
摘要由CSDN通过智能技术生成

一、实验要求

熟练掌握多协议多服务服务器的设计和实现方法。

二、实验步骤

1.super.c

int main(int argc, char *argv[]){
    struct service *psv,
            *fd2sv[NOFILE];
    int     fd, nfds;
    fd_set  afds, rfds;

    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);
    }
    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);
            }
        }
    }

}

void doTCP(struct service *psv)
{
    struct sockaddr_in fsin;
    unsigned int alen;
    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:
        close(ssock);
        return; /*parent*/
    }
    /*child*/

    for(fd = NOFILE; fd >=0; fd--)
    {
        /*close irrespective sock*/
        if(fd != ssock)
            close(fd);
    }
    psv->sv_func(ssock);
    exit(0);
}

void reaper(int sig)
{
    int status;
    while(wait3(&status, WNOHANG, (struct rusage *) 0) >= 0)
        /*empty*/;
}

2.sv_funcs.c

void TCPechod(int fd)
{
    char buf[BUFFERSIZE];
    int cc;
    printf("TCPecho: server\n");
    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));
    }
}

void UDPechod(int fd)
{
    struct sockaddr_in fsin;
    char buf[BUFFERSIZE];
    int cc;
    unsigned int alen;
    alen = sizeof(fsin);
    cc = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&fsin, &alen);
    if(cc == 0)
        return ;
    printf("UDPecho: server read: %s size:%d\n", buf, strlen(buf));

    sendto(fd, buf, cc, 0, (struct sockaddr*)&fsin, sizeof(fsin));
}

#define LINELEN 128
void
TCPdaytimed(int fd)
{
    char    buf[LINELEN], *ctime();
    time_t  now;

    printf("TCPdaytime: server\n");

    (void) time(&now);
    sprintf(buf, "%s", ctime(&now));
    (void) write(fd, buf, strlen(buf));
}

#define UNIXEPOCH   2208988800UL

void
UDPtimed(int sock)
{
    struct sockaddr_in fsin;
    char    buf[1];
    time_t  now;
    unsigned int    alen;

    alen = sizeof(fsin);
    if (recvfrom(sock, buf, sizeof(buf), 0,
            (struct sockaddr *)&fsin, &alen) < 0)
        errexit("recvfrom: %s\n", strerror(errno));

    printf("UDPtime: server\n");

    (void) time(&now);
    now = htonl((unsigned long)(now + UNIXEPOCH));
    sendto(sock, (char *)&now, sizeof(now), 0,
        (struct sockaddr *)&fsin, sizeof(fsin));
}


客户端代码TCPecho.c为例

3.

#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include <errno.h>  /*for errno*/
#define BUFFER_SIZE 4096

void TCPechod_client(int socket);

int main(int argc, char * argv[])
{
    char *host = "localhost";
    char *service = "echo";
    switch(argc)
    {
    case 1:
        break;
    case 3:
        service = argv[2];
    case 2:
        host = argv[1];
        break;
    default:
        fprintf(stderr, "usage: TCPfiletransfer [ host [port]]\n");
        exit(1);
    }
    int socket = connectTCP(host, service);
    TCPechod_client(socket);
    close(socket);
}
void TCPechod_client(int socket)
{
    char buf[BUFFER_SIZE];
    int cc;

    scanf("%s", buf);                 /*不能读空格*/
//    cc = read(0, buf, BUFFER_SIZE);     /*能读出空格,但会读取回车*/
    cc = write(socket, buf, sizeof(buf));
    if(cc < 0)
        errexit("client write: %s\n", strerror(errno));
    if(cc && read(socket, buf, cc) < 0)
        errexit("client read: %s\n", strerror(errno));
    printf("client read: %s\n",buf);

}

三、运行结果

编译,打开服务器:

客户端:

更新

Makefile的书写规则:

目标文件:依赖文件
(tab)编译规则

本博客中Makefile文件

tcp_server TCPdaytime TCPecho UDPecho UDPtime:tcp_server.o passiveTCP.o passiveUDP.o errexit.o passivesock.o sv_funcs.o TCPdaytime.o TCPecho.o UDPecho.o UDPtime.o connect.o connectsock.o
	gcc tcp_server.o passiveTCP.o passiveUDP.o errexit.o passivesock.o sv_funcs.o -o tcp_server
	gcc TCPdaytime.o connect.o errexit.o connectsock.o -o TCPdaytime
	gcc TCPecho.o connect.o errexit.o connectsock.o -o TCPecho
	gcc UDPecho.o connect.o errexit.o connectsock.o -o UDPecho
	gcc UDPtime.o connect.o errexit.o connectsock.o -o UDPtime
tcp_server.o:tcp_server.c
	gcc -c tcp_server.c -o tcp_server.o
passiveTCP.o:passiveTCP.c
	gcc -c passiveTCP.c -o passiveTCP.o
passiveUDP.o:passiveUDP.c
	gcc -c passiveUDP.c -o passiveUDP.o
errexit.o:errexit.c
	gcc -c errexit.c -o errexit.o
passivesock.o:passivesock.c
	gcc -c passivesock.c -o passivesock.o
sv_funcs.o:sv_funcs.c
	gcc -c sv_funcs.c -o sv_funcs.o
TCPdaytime.o:TCPdaytime.c
	gcc -c TCPdaytime.c -o TCPdaytime.o
TCPecho.o:TCPecho.c
	gcc -c TCPecho.c -o TCPecho.o
UDPecho.o:UDPecho.c
	gcc -c UDPecho.c -o UDPecho.o
UDPtime.o:UDPtime.c
	gcc -c UDPtime.c -o UDPtime.o
connect.o:connect.c
	gcc -c connect.c -o connect.o
connectsock.o:connectsock.c
	gcc -c connectsock.c -o connectsock.o
.PHONT:clean
clean:
	rm -rf *.o

参考:Makefile简单编写实例

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值