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

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

运行服务器时如果出现权限问题,记得在前面加sudo命令,赋予管理员权限执行

实验目的

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

实验原理

多协议的设计方案允许单个服务器线程同时管理针对同一个服务的 UDP 套接字和
TCP 套接字。在多服务的情况下,服务器可以为它所提供的一些甚至全部的服务管理 UDP 和 TCP 套接字。

实验步骤

服务器端:

1.passiveTCP.c
#include <stdio.h>
int passivesock( const char *service, const char *transport, const int qlen);
int passiveTCP(const char *service, int qlen){
	return passivesock( service, "tcp", qlen);
}
int passiveUDP(const char *service, int qlen){
	return passivesock( service, "udp", 0);
}
2.passivesock.c
#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>
#include <errno.h>
#include <stdio.h>
unsigned short portbase = 0;
int errexit(const char *format, ...);
int passivesock( const char *service, const char * transport, int qlen){
	struct hostent *phe;
	struct servent *pse;
	struct protoent *ppe;

	struct sockaddr_in sin;
	int s, type;
	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;
	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))) == 0 ){
		errexit("can't get \"%s\" service entry\n", service);
	}
	if( (ppe = getprotobyname( transport )) == 0 ){
		errexit("can't get \"%s\" protocol entry\n", transport);
	}
if( strcmp(transport, "udp") == 0){
		type = SOCK_DGRAM;
	}
	else{
		type = SOCK_STREAM;
	}
	s = socket(AF_INET, type, ppe->p_proto);
	printf("s=%d\n", s);
	printf("%d\n", ppe->p_proto);

	printf("%d\n", sin.sin_port);
	if( s < 0 ){
		errexit("can't create socket: %s\n", strerror(errno));
	}
	if( bind( s, (struct sockaddr *)&sin, sizeof(sin)) < 0 ){
		errexit("can't connect to %s:%s\n",  service, strerror(errno));
	}
	if( type == SOCK_STREAM && listen(s, qlen) < 0){
		errexit("cann't listen on %s port\n", service);
	}
	return s;
}
3.errexit.c
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
int errexit(const char *format, ...){
	va_list args;
	va_start(args, format);
	vfprintf(stderr, format, args);
	va_end(args);
	exit(1);
}
4.superd.c
#define _USE_BSD
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/errno.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define  UDP_SERV 0
#define  TCP_SERV 1
#define  NOSOCK	-1	/* an invalid socket descriptor */
struct service {
	char *sv_name; 
	char sv_useTCP; 
	int  sv_sock;
	void	(*sv_func)(int);
};



void TCPechod(int),	TCPchargend(int),	TCPdaytimed(int),	TCPtimed(int), UDPechod(int), UDPtimed(int) ;
int passiveTCP(const char *service, int qlen); 
int   passiveUDP(const char *service);
int errexit(const char *format, ...); 
void	doTCP(struct service *psv); 
void	reaper(int sig);
struct service svent[] =
{
	{ "echo", TCP_SERV, NOSOCK, TCPechod },
	{ "chargen", TCP_SERV, NOSOCK, TCPchargend },
	{ "daytime", TCP_SERV, NOSOCK, TCPdaytimed },
	{ "time", TCP_SERV, NOSOCK, TCPtimed },
	{ "echo", UDP_SERV, NOSOCK, UDPechod },
	{ "time", UDP_SERV, NOSOCK, UDPtimed },
	{ 0, 0, 0, 0 },
};
#ifndef  MAX
#define  MAX(x, y)   ((x) > (y) ? (x) : (y))
#endif	/* MAX */
#define QLEN	32
#define LINELEN	128
unsigned short portbase;	/* from passivesock()*/
 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);
			}
		}
	}
}
void doTCP(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);
}
/*------------------------------------------------------------------------

* reaper - clean up zombie children

*------------------------------------------------------------------------
*/ 
void reaper(int sig)
{
	int  status;
	while (wait3(&status, WNOHANG, (struct rusage *)0) >= 0)
			/* empty */;
}
5.vs_funcs.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUFFERSIZE	4096	/* max read buffer size	*/
void	TCPechod(int),	TCPchargend(int),	TCPdaytimed(int),	TCPtimed(int), UDPechod(int), UDPtimed(int);
int   errexit(const char *format, ...);
/*------------------------------------------------------------------------
* TCPecho - do TCP ECHO on the given socket
*------------------------------------------------------------------------
*/ 
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));
		}
	}
}
void UDPechod(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));
}
#define LINELEN	72
/*------------------------------------------------------------------------
* TCPchargend - do TCP CHARGEN on the given socket
*------------------------------------------------------------------------
*/ 
void TCPchargend(int fd)
{
	char c, buf[LINELEN+2]; /* print LINELEN chars + \r\n */
	c = ' ';
	buf[LINELEN] = '\r';
	buf[LINELEN+1] = '\n';
	while (1) {
		int  i;
		for (i=0; i<LINELEN; ++i) {
			buf[i] = c++; 
			if (c > '~'){
				c = ' ';
			}
		}
		if (write(fd, buf, LINELEN+2) < 0) {
			break;
		}
	}
}
/*------------------------------------------------------------------------
* TCPdaytimed - do TCP DAYTIME protocol
*------------------------------------------------------------------------
*/ 

void TCPdaytimed(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  */
/*------------------------------------------------------------------------
* TCPtimed - do TCP TIME protocol
*------------------------------------------------------------------------
*/ void TCPtimed(int fd)
{
	time_t	now;
	(void) time(&now);
	now = htonl((unsigned long)(now + UNIXEPOCH)); 
	(void) write(fd, (char *)&now, sizeof(now));
}
void UDPtimed(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));
}

实验结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Hello Spring

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值