停车场系统(C语言网络编程TCP io复用模型)

停车场系统(C语言网络编程TCP io复用模型)



实验要求

(1)、系统由三部分组成:分别包括:一个服务器,一个入口/出口管理程序,一个收银程序
(2)、服务器用指定的模型,其它部分可以采用任意模型
(3)、服务器功能:
(a) 接收并记录入口/出口管理程序发来的车牌号及记录车辆进入的时间,注意要检查车牌号不能与已经记录重复,如果重复,应通知入口/出口管理程序,不能开卡方行
(b) 计算车辆停留时间及费用,发给收银程序
(c) 通知入口/出口管理程序放行车辆,并删除车牌号
(4)、入口/出口管理程序功能
(a) (1)接收用户输入的车牌号发往服务器,再接收服务器应答消息,并显示是否方向车辆驶入(显示字符“欢迎光临”表示放行车辆驶入)
(b) 接收服务器放行消息,放行车辆(显示字符“谢谢惠顾”表示放行车辆)
(5)、收银程序功能:
(a) 将要离场车辆车牌发到服务器。
(b) 接收服务器发来的停车时间及费用,并显示
(c) 收银成功或失败的消息发往服务器


一、实现思路:

(1)、服务器采用io复用模型,用来接收出口入口程序和收银程序发来的内容,并采用利用缓冲区第一位作为表示来区分程序消息类别
(2)、出口入口程序采用创建多线程的方式,单独创建一个线程来给用户输入数据,主线程来接受服务器发来的消息
(3)、收银程序实现最为简单,利用最为普通的客户端模型即可

二、代码实现

1.服务器

代码如下(示例):

// 服务器.cpp : Defines the entry point for the console application.
//服务器

#include "stdafx.h"
#include <string.h>
#include<time.h>

//定义一个结构体,其中包含车牌号和对应的入库时间
struct Car{
	char license[100][20];//存储车牌号
	time_t start[100];//存储入库的时间
	//int count;//记录车库中车子的数量
};

SOCKET client;
struct Car car;
int count = 0;

void Rukou(SOCKET s,char buf[]){
	char data[2] = {0};
	int flag = 1;
	for(int j=0;j<100;j++){
		if(strcmp(buf,car.license[j])==0){
			flag = 0;
			break;
		}//strcmp
	}//for
	if(flag==1){
		int len = strlen(buf);
		for(int k=0;k<len;k++){
				car.license[count][k] = buf[k];					
		}
		car.start[count] = time(NULL);
		count++;
		data[0] = '2';
		int c = send(s,data,1,0);
		if(c<=0){
			printf("发送失败!\n");
		}
	}//if(flag==1)
	else{
		data[0] = '3';
		int b = send(s,data,1,0);
		if(b<=0){
			printf("发送失败!\n");
		}
	}//else if(flag==1)
}
//转换函数,将我们的时间和收费转为字符串存储到data数组中去
void trans(int hours,int min,int sec,int money,char *data){
	int offset;
	sprintf(data,"%d",hours);
	offset = strlen(data);
	data[offset] = 208;
	data[offset+1] = 161;
	data[offset+2] = 202;
	data[offset+3] = 177;
	offset = strlen(data);
	sprintf(data+offset,"%d",min);
	offset = strlen(data);
	data[offset] = 183;
	data[offset+1] = 214;
	data[offset+2] = 214;
	data[offset+3] = 211;
	offset = strlen(data);
	sprintf(data+offset,"%d",sec);
	offset = strlen(data);
	data[offset] = 195;
	data[offset+1] = 235;
	data[offset+2] = '#';
	offset = strlen(data);
	sprintf(data+offset,"%d",money);
	offset = strlen(data);
	data[offset] = 212;
	data[offset+1] = 170;
	data[offset+2] = '#';
}

void Chuku(SOCKET s,char buf[]){
	int p;
	int bet;
	int money = 2;
	int hours=0,min=0,sec=0;
	char data[100] = {0};
	time_t end;
	for(int j=0;j<100;j++){
		if(strcmp(buf,car.license[j])==0){
			p = j;
			break;
		}//strcmp
	}//for
	end = time(NULL);
	bet = end - car.start[p];
	hours = bet / 3600;
	bet = bet % 3600;
	min = bet /60;
	sec = bet % 60;
	if(hours){//6块
		money = money + 5 * hours;
	}
	if(min){//半小时3元
		money = money + min / 10;
	}
	//printf("时间为:%d小时%d分钟%d秒\t",hours,min,sec);
	trans(hours,min,sec,money,data);
	int b = send(s,data,strlen(data),0);
	if(b<=0){
		printf("发送失败!");
	}
	else{
aa:
		memset(data,0,100);
		int c = recv(s,data,100,0);
		if(c>0){
			if(data[0]=='7'){
				printf("%s收银成功\n",buf);
				memset(data,0,100);
				data[0] = '4';
				int d = send(client,data,1,0);
				if(d<=0){
					printf("发送失败");
				}
				memset(car.license[p],0,20);
			}
			else if(data[0]=='8'){
				printf("%s收银失败\n",buf);
				goto aa;
			}
		}
	}
}

int main(int argc, char* argv[])
{
	//加载windows socket DDL
	WSADATA	wsaData;
	int iResult;
	iResult = WSAStartup(MAKEWORD(2,2),&wsaData);
	printf("*******************\n");
	printf("*                 *\n");
	printf("*停车场管理服务器 *\n");
	printf("*                 *\n");
	printf("*******************\n");
	if(iResult==0){
		printf("服务器启动成功\n");
	}
	else{
		printf("服务器启动失败!\n");
	}
	//服务器的地址结构
	struct sockaddr_in serveraddr;
	int len1 = sizeof(serveraddr);
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	serveraddr.sin_port = htons(4000);
	//创建服务器套接字
	SOCKET serversocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(serversocket==-1){
		printf("绑定套接字失败!");
		WSACleanup();
		return 0;
	}
	//客户端的地址结构
	struct sockaddr_in clientaddr;
	int len2 = sizeof(serveraddr);
	//利用bind绑定服务器套接字
	int r;
	r = bind(serversocket,(struct sockaddr *)&serveraddr,len1);
	if(r!=0){
		printf("服务器绑定失败!\n");
	}
	//利用listen将服务器转为被动监听模式
	listen(serversocket,SOMAXCONN);
	//缓冲区
	char buf[100] = {0};
	//car.count = 0;
	//初始化i/o复用所用的bianl
	fd_set fdRead,fdsocket;
	FD_ZERO(&fdRead);
	FD_ZERO(&fdsocket);
	FD_SET(serversocket,&fdsocket);
	//进行i/o复用的操作
	while(1){
		//利用fdRead来存储触发了时间的套接字
		fdRead = fdsocket;
		int r;
		r = select(0,&fdRead,NULL,NULL,NULL);
		//处理事件
		if(r>0){
			for(int i=0;i<fdsocket.fd_count;i++){
				if(FD_ISSET(fdsocket.fd_array[i],&fdRead)){
					if(fdsocket.fd_array[i]==serversocket){
						SOCKET clientsocket = accept(serversocket,(struct sockaddr *)&clientaddr,&len2);
						if(clientsocket==-1){
							printf("接受失败!\n");
						}
						FD_SET(clientsocket,&fdsocket);
					}//fdsocket.fd_array[i]==serversocket
					else{
						int l;
						memset(buf,0,100);
						l = recv(fdsocket.fd_array[i],buf,100,0);
						if(buf[0]=='1'){//出口入口程序发来车牌号
							Rukou(fdsocket.fd_array[i],buf+1);
						}
						else if(buf[0]=='9'){
							printf("出口入口程序连接成功\n");
							client = fdsocket.fd_array[i];

						}
						else if(buf[0]=='6'){
							printf("收银程序连接成功\n");
						}
						else if(buf[0]=='5'){
							Chuku(fdsocket.fd_array[i],buf+1);
						}
					}//else:fdsocket.fd_array[i]==serversocket
				}//FD_ISSET
			}//for
		}//r>0
	}
	closesocket(serversocket);
	WSACleanup();
	return 0;
}

注意点:这里trans函数用来将停车的时间和收费几种放入数据中存储,最后一起发送

2.出口入口程序

代码如下(示例):

// 出口入口程序.cpp : Defines the entry point for the console application.
//出口入口程序

#include "stdafx.h"

char buf[100] = {0};

DWORD WINAPI Thread(LPVOID p){
	printf("输入要进入车库车的车牌号:\n");
	SOCKET s = (SOCKET)p;
	while(1){
		memset(buf,0,100);
		buf[0] = '1';
		scanf("%s",buf+1);
		int l;
		l = send(s,buf,strlen(buf+1)+1,0);
		if(l<0){
			printf("发送失败!\n");
		}
		else if(l==0){
			printf("服务器关闭\n");
		}
	}
	return 0;
}

int main(int argc, char* argv[])
{
	//加载windows socket DDL
	WSADATA	wsaData;
	int iResult;
	iResult = WSAStartup(MAKEWORD(2,2),&wsaData);
	printf("*******************\n");
	printf("*                 *\n");
	printf("*  出口入口程序   *\n");
	printf("*                 *\n");
	printf("*******************\n");
	if(iResult==0){
		printf("出口入口程序启动成功\n");
	}
	else{
		printf("出口入口程序启动失败\n");
		return 0;
	}
	//创建套接字
	SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(s==-1){
		printf("套接字绑定失败!\n");
		WSACleanup();
		return 0;
	}
	//指定服务器的地址结构
	struct sockaddr_in serveraddr;
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	serveraddr.sin_port = htons(4000);
	//利用connect连接服务器
	int r;
	r = connect(s,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
	if(r==-1){
		printf("连接服务器失败!\n");
		closesocket(s);
		WSACleanup();
		return 0;
	}
	else{
		printf("连接服务器成功\n");
	}
	//直接创建一个线程用来进行数据的发送操作
	CreateThread(0,0,Thread,(LPVOID)s,0,0);
	//循环接受服务器的消息
	char data[100] = {0};
	data[0] = '9';
	send(s,data,1,0);
	while(1){
		int l;
		memset(data,0,100);
		l = recv(s,data,100,0);
		if(l>0){
			if(data[0]=='2'){
				printf("*******************\n");
				printf("*     欢迎光临    *\n");
				printf("*******************\n");
			}
			else if(data[0]=='3'){
				printf("*******************\n");
				printf("*     禁止进入    *\n");
				printf("*******************\n");
			}
			else if(data[0]=='4'){
				printf("*******************\n");
				printf("*     谢谢惠顾    *\n");
				printf("*******************\n");
			}
		}
	}
	closesocket(s);
	WSACleanup();
	return 0;
}


这里就是将用户输入单独开辟了一个线程,这样可以即可发数据又可收数据

3.收银程序

// 收银程序.cpp : Defines the entry point for the console application.
//收银程序代码

#include "stdafx.h"
#include <string.h>

int main(int argc, char* argv[])
{
	//加载windows socket DDL
	WSADATA wsaData;
	int iResult;
	iResult = WSAStartup(MAKEWORD(2,2),&wsaData);
	printf("*******************\n");
	printf("*                 *\n");
	printf("*    收银程序     *\n");
	printf("*                 *\n");
	printf("*******************\n");
	if(iResult == 0){
		printf("收银程序启动成功\n");
	}
	else{
		printf("收银程序启动失败\n");
	}
	//创建套接字
	SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(s==-1){
		printf("套接字绑定失败!\n");
		WSACleanup();
		return 0;
	}
	//指定服务器的地址结构
	struct sockaddr_in serveraddr;
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	serveraddr.sin_port = htons(4000);
	//利用connect连接服务器
	int r = connect(s,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
	if(r==-1){
		printf("连接服务器失败!\n");
		closesocket(s);
		WSACleanup();
		return 0;
	}
	else{
		printf("连接服务器成功\n");
	}
	//用户收发数据的缓冲区
	char buf[100] = {0};
	char min[20] = {0};
	char money[20] = {0};
	int flag;
	//与服务器进行车子离库的交互操作
	buf[0] = '6';
	int a = send(s,buf,1,0);
	if(a<=0){
		printf("发送失败\n");
	}
	memset(buf,0,100);
	while(1){
		printf("请输入要离场的车牌号:");
		buf[0] = '5';
		scanf("%s",buf+1);
		int l;
		l = send(s,buf,strlen(buf+1)+1,0);
		if(l>0){
			memset(buf,0,100);
			memset(min,0,20);
			memset(money,0,20);
			int j=0;
			int t;
			t = recv(s,buf,100,0);
			if(t>0){
				for(int i=0;buf[i]!='#';i++){
					min[i] = buf[i];
				}
				i = i + 1;
				for(;buf[i]!='#';i++){
					money[j] = buf[i];
					j++;
				}
				printf("停车的时间为:%s\t应收费:%s\n",min,money);
				memset(buf,0,100);
aa:
				printf("请输入是否收银成功(1、是,0、否):\n");
				scanf("%d",&flag);
				if(flag==1){
					int d;
					buf[0] = '7';
					d = send(s,buf,1,0);
					if(d<=0){
						printf("发送失败!\n");
					}
				}
				else if(flag == 0){
					int b;
					buf[0] = '8';
					b = send(s,buf,1,0);
					if(b<=0){
						printf("发送失败!\n");
					}
					printf("请重新收费!!\n");
					goto aa;
				}
			}
			else if(t==0){
				printf("服务器关闭!\n");
				break;
			}
			else{
				printf("接受失败!\n");
			}
		}
		else if(l==0){
			printf("服务器关闭!\n");
			break;
		}
		else{
			printf("发送失败!\n");
		}
	}
	closesocket(s);
	WSACleanup();
	return 0;
}



运行截图

在这里插入图片描述

总结

以上就是实验的全部内容,总体难度偏容易;主要就是突破点就是消息种类的判断,出口入口程序套接字的储存和客户端如何实现多线程

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值