一、实验要求
熟练掌握多协议多服务服务器的设计和实现方法。
二、实验步骤
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