Linux简单的投票系统

Server

内存映射,未考虑互斥

 #include <stdlib.h>  
 #include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
 #include <netdb.h>
 #include <sys/types.h>
 #include <sys/socket.h> 
 #include <arpa/inet.h>
 #include <sys/wait.h> 
 #include <signal.h> 

#include <sys/mman.h>
#include <fcntl.h>


#define VOTE_REQ 0xA9 		/* 投票请求 */ 
#define INQY_REQ 0xAA	 	/* 投票查询 */ 
#define INQY_RES 0xA8 		/* 查询应答 */ 
#define HSIZE sizeof (struct vote) /* 投票协议头部大小 */ 
#define IDSIZE 1 			/* 球队ID大小 */ 
#define BUFSIZE 128
#define VISIZE sizeof(struct voteinfo) 
#define MAXTEAM 32 			/* 球队数目 */ 

static unsigned char buf[BUFSIZE]; /* 协议单元 */


struct vote
{
	unsigned char type : 2, /* 协议类型 */
				  prec : 6; /* 前导符101010 */
	unsigned short len; /* 协议数据长度 */
	//unsigned char content[0];
}__attribute__((packed));

struct voteinfo
{
	unsigned char id; /* 球队ID */
	unsigned int num; /* 球队得票数 */
}__attribute__((packed));//按 1 进行字节对齐

/*
	*投票,查询请求消息
	*id   待查询球队ID列表
	*vote  为真代表投票请求,
	*	   为假代表查询请求
*/
int make_vote(unsigned char *id, int vote);
/*
	*查询应答消息
	*voteinfo,球队投票信息列表
	*num,待查询球队ID的个数
*/
int reply_vote(struct voteinfo *votelist, int num);
/*
	*输入: buf 来客户端的协议    【前导符(6位) - 协议类型(2位)】 【长度(2Bytes)】 内容(...)
	*格式 0:[101010]-[00] [个数x5 + 3] [ID+Counts 1+4 Bytes]...
	*格式 1:[101010]-[01] [恒为4] [球队ID,1Byte]
	*格式 2:[101010]-[10] [个数+3] [ID 1 Bytes]...
	*voteArr 服务器存储的球队投票信息
	*输出:
	*votelist 存储查询到的球队投票信息
*/
int analyze(const unsigned char *buf, struct voteinfo *voteArr, struct voteinfo *votelist);
/* 初始化函数 */
void Init_vote(struct voteinfo *voteArr);


static void sigchld_handler(int signo)
{
	pid_t pid;
	int status;
	char msg[] = "SIGCHLD caught\n";

	write(STDOUT_FILENO, msg, sizeof(msg));
	/* 等待已退出的所有子进程 */
	do {
		pid = waitpid(-1, &status, WNOHANG);
	} while (pid > 0);
}

int main(int argc, char *argv[])
{
	/* 解析协议信息缓存数组 */
	struct voteinfo *votelist= (struct voteinfo *)malloc(MAXTEAM * sizeof(struct voteinfo));
	memset(votelist, 0, sizeof(votelist));
	/*储存球队信息数组 -->内存消息映射*/
	struct voteinfo *voteArr = (struct voteinfo *)mmap(NULL, sizeof(struct voteinfo) *32, 
		PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
	memset(voteArr, 0, sizeof(voteArr));
	//初始化投票信息数组
	Init_vote(voteArr);

	int sockfd; /* 服务器套接字 */
	int new_fd; /* 服务器连接套接字 */
	struct sockaddr_in server_addr; /* 服务器监听套接字 */
	struct sockaddr_in client_addr; /* 客户端IP地址 */

	socklen_t size;
	int portnumber;
	struct sigaction child_action;
	pid_t pid;
	int z;

	memset(&child_action, 0, sizeof(child_action));
	child_action.sa_flags |= SA_RESTART;
	child_action.sa_handler = sigchld_handler;
	if (sigaction(SIGCHLD, &child_action, NULL) == -1)
		perror("Failed to ignore SIGCHLD");

	if (argc != 2)
	{
		fprintf(stderr, "Usage: %s portnumber\a\n", argv[0]);
		exit(1);
	}

	if ((portnumber = atoi(argv[1])) < 0)
	{
		fprintf(stderr, "Usage: %s portnumber\a\n", argv[0]);
		exit(1);
	}

	/* 创建服务器监听套接字 */
	if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
	{
		fprintf(stderr, "Socket error: %s\a\n", strerror(errno));
		exit(1);
	}

	/* 为监听套接字准备IP地址和端口 */
	memset(&server_addr, 0, sizeof server_addr);
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_port = htons(portnumber);

	/* 绑定套接字到指定地址和端口 */
	if ((bind(sockfd, (struct sockaddr *)(&server_addr), sizeof server_addr)) == -1)
	{
		fprintf(stderr, "Bind error: %s\a\n", strerror(errno));
		exit(1);
	}

	/* 监听 */
	if (listen(sockfd, 128) == -1)
	{
		fprintf(stderr, "Listen error: %s\n\a", strerror(errno));
		exit(1);
	}
	printf("sockfd = %d\n", sockfd);
	printf("waiting for the client's request...\n");
	char *str = "Vote successfully!";
	while (1)
	{
		size = sizeof(struct sockaddr_in);
		int bufsize = 0;//cun chu buf size
		/* 接收一个客户端连接并创建服务器连接套接字 */
		if ((new_fd = accept(sockfd, (struct sockaddr *)(&client_addr), &size)) == -1)
		{
			fprintf(stderr, "Accept error: %s\a\n", strerror(errno));
			exit(1);
		}

		fprintf(stdout, "Server got connection from %s\n",
			inet_ntoa(client_addr.sin_addr));

		pid = fork();

		switch (pid)
		{
		case -1:
			perror("fork failed");
			exit(1);

		case 0:
			puts("Entering the child\n");
			for (;;)
			{
		
				z = read(new_fd, buf, sizeof buf);
				if (z <= 0)
				{
					break;
				}
				printf("buf : 0x%x--0x%x\n", *buf, *(buf + 1));
				if(*buf == 0xa9)
				{
					z = analyze(buf, voteArr, votelist);
					if(z)
						write(new_fd, str, strlen(str));
				}
				else if(*buf == 0xaa)
				{
					printf("----->read succesfully!\n");
					int reNum = analyze(buf, voteArr, votelist);
					//printf("qiu dui Num = %d\n", reNum);
					bufsize = reply_vote(votelist, reNum);
					/* 将buf发送给客户端 */
					z = write(new_fd, buf, bufsize);
					//printf("bufinfo: 0x%x--0x%x--0x%x\n", *buf, *(buf + 1), *(buf + 4));
					int index = 0;
					while(z <= 0)
					{
						index++;
						printf("----->write failed!\n");
						z = write(new_fd, buf, strlen(buf));
						if(index >= 10)
							break;
					}
					if(index < 10)
					{
						printf("------>send success!\n");
						memset(buf, 0, sizeof(buf));
					}
				}
			}
			printf("Child process: %d exits.\n", getpid());
			close(new_fd);
			exit(0);
		}
	
	}
	/* 解除内存映射关系 */	
	munmap(voteArr, sizeof(struct voteinfo) * 32);
	if(votelist != NULL)
	{
		free(votelist);
		votelist == NULL;	
		printf("----->free success!\n");	
	}
    	return 0;
}


int reply_vote(struct voteinfo *votelist, int num)
{
	struct vote v;
	unsigned char type = INQY_RES;
	memset(buf, 0, BUFSIZE);
	*(unsigned char *)&v = type; /* 设置前导符和协议类型 */
	v.len = HSIZE + VISIZE * num;
	memcpy(buf, &v, HSIZE); /* 构造协议头部 */
	/* 设置投票球队得票信息 */
	memcpy(buf + HSIZE, votelist, VISIZE * num);
	return v.len;
}


int analyze(const unsigned char *buf, struct voteinfo *voteArr, struct voteinfo *votelist)
{
	if(NULL == voteArr || NULL == votelist)
	{
		return -1;
	}
	if (buf == NULL)
	{
		return -1;
	}

	if (*buf == 0xa9)
	{
		int i = 0;
		for (; i < MAXTEAM; ++i)
		{
			//printf("%c ", *(buf + 3));
			if (*(buf + 3) == voteArr[i].id)
			{	
				
				voteArr[i].num++;
				printf("voteArr[%d].num = %d\n", i, voteArr[i].num);
				break;
			}
		}
		if( i < MAXTEAM)
		{
			printf("%d队获得一票 \n", (unsigned int)voteArr[i].id - 48);
			return 1;
		}
		else
		{
			printf("no such ID\n");
		}
	}
	else if (*buf == 0xaa)
	{
		int i = 0;
		unsigned short idNum = *(buf + 1) - 3;
		buf += 3;
		memset(votelist, 0, sizeof(votelist));		
		for (; i < idNum; ++i)
		{
			votelist[i].id = *buf;
			votelist[i].num = voteArr[votelist[i].id - 49].num;
			buf++;
		}
		return i;
	}
}

void Init_vote(struct voteinfo *voteArr)
{
	int i = 0;
	for (; i < MAXTEAM; ++i)
	{
		voteArr[i].id = (unsigned char)(i + 49);
		voteArr[i].num = 0;
	}
	
}

Client

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


#define VOTE_REQ 0xA9 		/* 投票请求 */ 
#define INQY_REQ 0xAA	 	/* 投票查询 */ 
#define INQY_RES 0xA8 		/* 查询应答 */ 
#define HSIZE sizeof(struct vote) /* 投票协议头部大小 */ 
#define IDSIZE 1 			/* 球队ID大小 */ 
#define BUFSIZE 128
#define VISIZE sizeof(struct voteinfo) 
#define MAXTEAM 32 			/* 球队数目 */ 

static unsigned char buf[BUFSIZE]; /* 协议单元 */

struct vote
{
	unsigned char type : 2, /* 协议类型 */
		        prec : 6; /* 前导符101010 */
	unsigned short len; /* 协议数据长度 */
	unsigned char content[0];
}__attribute__((packed));

struct voteinfo
{
	unsigned char id; /* 球队ID */
	unsigned int num; /* 球队得票数 */
}__attribute__((packed));

/*投票,查询请求消息
*id,待查询球队ID列表
*vote, 为真代表投票请求,
*为假代表查询请求*/
int make_vote(unsigned char *id, int vote);
/*解析协议*/
int analyze(const unsigned char *buf, struct voteinfo *votelist);

int main(int argc, char *argv[])
{

	/* 球队投票信息数组 */
	struct voteinfo *votelist = (struct voteinfo*)malloc(sizeof(struct voteinfo) * MAXTEAM); 
	memset(votelist, 0, sizeof votelist);

	int sockfd; /* 客户端套接字 */

	struct sockaddr_in server_addr; /* 服务器IP地址 */
	struct hostent *host;		//主机信息结构体
	int portnumber;
	int nbytes;
	int z;

	if (argc != 3)
	{
		fprintf(stderr, "Usage: %s hostname portnumber\a\n", argv[0]);
		exit(1);
	}
	if ((host = gethostbyname(argv[1])) == NULL)
	{
		fprintf(stderr, "Gethostname error\n");
		exit(1);
	}
	if ((portnumber = atoi(argv[2])) < 0)
	{
		fprintf(stderr, "Usage: %s hostname portnumber\a\n", argv[0]);
		exit(1);
	}
	/* 创建客户端套接字 */
	if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
	{  
		fprintf(stderr, "Socket Error: %s\a\n", strerror(errno));
		exit(1);
	} 

	/* 创建服务器地址 */
	memset(&server_addr, 0, sizeof server_addr);
	server_addr.sin_family = PF_INET;
	server_addr.sin_port = htons(portnumber);
	server_addr.sin_addr = *((struct in_addr *)host->h_addr);
	printf("sockfd = %d\n", sockfd);
	/* 连接服务器 */
	if (connect(sockfd, (struct sockaddr *)(&server_addr), sizeof server_addr) == -1)
	{
		fprintf(stderr, "Connect Error: %s\a\n", strerror(errno));
		exit(1);
	}
	printf("connected to server %s\n", inet_ntoa(server_addr.sin_addr));

	for (;;)
	{
		int index = -1;		
		unsigned int num[MAXTEAM] = {0};
		unsigned char arr[MAXTEAM] = {0};
		int reNum = 0;
		printf("请输入信息(1:投票 0:查询票数情况)(输入其他则退出):\n");
		scanf("%d", &index);
		getchar(); // 获取回车键 '10'
		if (index == 0)
		{
			printf("请输入你想要查询的球队ID(1-32)(按0退出):\n");
			for(; index < MAXTEAM; ++index)
			{
				scanf("%d", &num[index]);
				getchar();
				if(num[index] == 0 || num[index]<1 || num[index] > 32)
				{	
					if(num[index] == 0)
					{
						index = 0;
						break;
					}
					else
					{
						printf("请输入1-32之间的队号\n");
						index--;
						continue;
					}
				}
				arr[index] = (unsigned char)(num[index] + 48);
				
			}
			
		}
		else if(index == 1)
		{
			for(;;)
			{
				printf("请输入你想要投票的球队ID(1-32):\n");
				scanf("%d", &num[0]);
				getchar();
				if(num[0] >= 1 && num[0] <= 32)
				{
					arr[0] = (unsigned char)(num[0] + 48);
					break;
				}
				else
				{
					printf("请正确输入!\n");
					continue;
				}
			}
		}
		else
		{
			break;
		}
		if ((reNum = make_vote(arr, index)) <= 0)
		{
			fprintf(stderr, "make_vote failed: %s\n", strerror(errno));
			printf("make_vote failed\n");
			exit(1);
		}
		
		z = write(sockfd, buf, reNum);
		while(z <= 0)
		{
			printf("----->write failed!\n");
			z = write(sockfd, buf, reNum);
		}
		printf("----->send success!\n");
		printf("send--->bufInfo : 0x%x--0x%x\n", *buf, *(buf + 1));
		memset(buf, 0, sizeof buf);
		/*
		* 从客户端套接字中读取服务器发回的应答
		*/
		if ((nbytes = read(sockfd, buf, sizeof buf)) == -1)
		{
			fprintf(stderr, "Read Error: %s\n", strerror(errno));
			exit(1);
		}
		if (nbytes == 0) /* 遇到EOF */
		{
			printf("server has closed the socket.\n");
			break;
		}
		
		if(*buf == 0xa8)
		{
			printf("recv-->bufInfo : 0x%x--0x%x\n", *buf, *(buf + 1));
			int renum = analyze(buf, votelist);
			int i = 0;
			for(i; i < renum; ++i)
			{
				printf("ID: %d, vote:%d\n", votelist[i].id - 48, votelist[i].num);
			}
		}
		else
			printf("Server : %s\n", buf);
	}
	close(sockfd);
	return 0;
}


/*id: 0 - 255*/
int make_vote(unsigned char *id, int vote)
{
	struct vote v;
	unsigned char type;
	int num;
	num = strlen(id); /* 获得球队个数 */
	if (vote)
		type = VOTE_REQ;
	else
		type = INQY_REQ;	/* 投票查询 */ 
	memset(buf, 0, BUFSIZE);
	*(unsigned char *)&v = type; /* 设置前导符和协议类型 */
	v.len = HSIZE + IDSIZE * num;
	memcpy(buf, &v, HSIZE); /* 构造协议头部 */
	if (num)
		memcpy(buf + HSIZE, id, IDSIZE * num); /* 球队ID */
	return v.len;
}

/*
输入: buf 来自服务器    前导符(6位) - 协议类型(2位) 长度(2Bytes) 内容(...)
格式 0:[101010]-[00] [个数x5 + 3] [ID+Counts 1+4 Bytes]...
格式 1:[101010]-[01] [恒为4] [球队ID,1Byte]
格式 2:[101010]-[10] [个数+3] [ID 1 Bytes]...

输出:
votelist 更新
*/
int analyze(const unsigned char *buf, struct voteinfo *votelist)
{
	//main 已判断buf不为空
	int i = 0;
	int idnum = *(buf + 1) / 5;
	buf += 3;
	for( i; i < idnum; ++i)
	{
		votelist[i].id = *(buf++);
		votelist[i].num = (unsigned int)*buf;
		buf += 4;
	}
	return idnum;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值