小车远程监控系统课程设计大学论文.docx
《小车远程监控系统课程设计大学论文.docx》由会员分享,可在线阅读,更多相关《小车远程监控系统课程设计大学论文.docx(14页珍藏版)》请在冰豆网上搜索。
小车远程监控系统课程设计大学论文
课程设计Ⅱ报告
(2016/2017学年第一学期)
题目:
小车远程监控系统
专业
计算机科学与技术
学生姓名
孙烨
班级学号
B13040402
指导教师
邹志强
指导单位
计算机学院、软件学院
日期
2017.01.03-01.12
指导教师成绩评定表
学生姓名
班级学号
专业
计算机科学与技术
评分内容
评分标准
优秀
良好
中等
差
平时成绩
认真对待课程设计,遵守实验室规定,上机不迟到早退,不做和设计无关的事
设计成果
设计的科学、合理性
功能丰富、符合题目要求
界面友好、外观漂亮、大方
程序功能执行的正确性
程序算法执行的效能
设计报告
设计报告正确合理、反映系统设计流程
文档内容详实程度
文档格式规范、排版美观
验收答辩
简练、准确阐述设计内容,能准确有条理回答各种问题,系统演示顺利。
评分等级
指导教师
简短评语
指导教师签名
日期
2017-01-12
备注
评分等级有五种:
优秀、良好、中等、及格、不及格
小车远程监控系统
一、课题内容和要求
服务器端:
1、利用linuxC实现服务器;
2、服务器端使用多进程实现多客户网络服务;
3、服务器多个进程之间需要使用IPC通信(进程间通信);
客户端:
1、在linuxC下实现网络客户端;
为了实现同时读阻塞的键盘和阻塞的网络,要求使用多路IO实现同时阻塞的读键盘和读网络。
服务器客户端的网络通信:
这里要求采用TCP协议进行通信,实现所要求的S/C模式,并且要求实现多客户服务。
二、需求分析
服务器端:
1、服务器端利用随机数模拟向串口读取传感数据,需要模拟的传感数据要求有:
温度、湿度、光照。
2、服务器利用网络接收客户端发送过来的设备控制信号,通过写驱动,实现对底层硬件的控制,这里使用打印显示的方式模拟。
3、在进程之间IPC通信时,要求使用文件锁或信号量实现资源保护。
客户端:
1、客户端能够通过网络通信实现接收服务器端传输过来的传感数据,并将传感数据打印到屏幕上显示。
2、客户端能够从键盘输入控制信号,并且通信将控制信号发送给服务器。
3、客户端要求实现控制信号有,开灯、关灯,开空调、关空调、开启小车、停小车等。
三、概要设计
服务器客户端
四、详细设计(格式:
宋体,4号,加粗,两端对齐)
各个算法实现的源程序(可以是一组源程序,每个功能模块采用不同的函数实现),源程序要按照写程序的规则来编写。
要结构清晰,重点函数的重点变量,重点功能部分要加上清晰的程序注释。
头文件(cs.h)
TimesNewRxoman#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#defineSER_PORT5010
#defineSER_IP"127.0.0.1"
#defineMAX_SIZE2048
#defineMAX_CONNECT20//最大可连接的客户端数量
#defineCHPTH_COUNT3
#definePTH_EIXT1
intskfd=0;
intcfd=0;
intret=0;
voiderr_fun(constchar*constfile_name,intline,constchar*constfun_name,interr_no){
fprintf(stderr,"%s%d%s:
%s\n",file_name,line,fun_name,strerror(err_no));
exit(-1);
}
voidsignal_fun(inta){
intret=shutdown(skfd,SHUT_WR);
if(ret<0)err_fun(__FILE__,__LINE__,"shutdown",errno);
printf("\nShutsDown!
!
!
\n");
exit(0);
}
structglobal_va
{
charpth_exit_flag;
pthread_mutex_tmutex;
}glb_va={0,PTHREAD_MUTEX_INITIALIZER};
structpthread_arg{
intfd;
pthread_tpthid;
intpthnum;};
客户端代码:
#include"cs.h"
intmain(void){
chardata_send[MAX_SIZE]={0};
chardata_recv[MAX_SIZE]={0};
structsockaddr_ins_addr={0};
intflag=0;
skfd=socket(PF_INET,SOCK_STREAM,0);/*创建一个套接字文件,返回一个用于监听用客户上线用的文件描述符*参数1:
域(协议族)*/
if(skfd<0)err_fun(__FILE__,__LINE__,"socket",errno);
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(SER_PORT);
s_addr.sin_addr.s_addr=inet_addr(SER_IP);
ret=connect(skfd,(structsockaddr*)&s_addr,sizeof(s_addr));
if(ret<0)err_fun(__FILE__,__LINE__,"accept",errno);
signal(SIGINT,signal_fun);//信号处理函数,按下ctrlc则退出
while
(1){
printf("*****************************************************************\n");
printf("*****************************************************************\n");
printf("*********************请选择序号控制智能小车**********************\n");
printf("*********************0,车内环境信息**********************\n");
printf("*********************1,关闭小车空调**********************\n");
printf("*********************2,打开小车空调**********************\n");
printf("*********************3,关闭小车灯**********************\n");
printf("*********************4,打开小车灯**********************\n");
printf("*********************5,启动小车**********************\n");
printf("*********************6,停止小车**********************\n");
printf("*********************按Ctrl+C退出**********************\n");
printf("*****************************************************************\n");
printf("*****************************************************************\n");
printf("请输入控制序号->");
scanf("%s",data_send);
flag=atoi(data_send);
if(flag>6||flag<0)/*值域判断*/printf("输入错误,请重新输入。
\n");
else{
ret=write(skfd,data_send,MAX_SIZE);
if(ret<0)err_fun(__FILE__,__LINE__,"writeerror",errno);
ret=read(skfd,data_recv,MAX_SIZE);
if(ret<0)err_fun(__FILE__,__LINE__,"readerror",errno);
printf("服务器消息->%s\n",data_recv);
memset(data_send,0,MAX_SIZE);
memset(data_recv,0,MAX_SIZE);
}sleep(1.5);
}
return0;
}
服务器端:
#include"cs.h"
intcount_client=0;//存储当前的客户端数量
staticvoidpthread_fun(void*cfd)
{
count_client++;
inttempfd=0;
inti_recvBytes;
chardata_recv[MAX_SIZE]={0};
chardata_send[MAX_SIZE]={0};
strcpy(data_send,"已执行操作");
structpthread_arg*p=(structpthread_arg*)cfd;
intfd=p->fd;
while
(1){
printf("\n等待请求...\n");
if(glb_va.pth_exit_flag==PTH_EIXT){
pthread_mutex_unlock(&glb_va.mutex);
break;
}
i_recvBytes=read(fd,data_recv,MAX_SIZE);
if(i_recvBytes==0){
printf("客户%d下线\n",fd-3);
break;
}
if(i_recvBytes==-1){
fprintf(stderr,"读错误!
\n");
break;
}
printf("从客户:
%d\t收到控制序号%s\n",fd-3,data_recv);
if(strcmp(data_send,"quit")==0){
printf("拒绝请求!
\n");break;
}pthread_mutex_lock(&glb_va.mutex);//增加互斥锁
sleep(3);
time_ttim;
floatillumination=0,humid=0,temperature=0;//定义湿度,光照,温度
chart[16];
if(atoi(data_recv)>=0&&atoi(data_recv)<7){
switch(atoi(data_recv)){
case0:
tim=time(NULL);
srand(tim);
illumination=(float)(rand()%100);//随机生成
humid=(float)(rand()%100);
temperature=(float)(rand()%40);
strcpy(data_send,"车内环境信息:
光照");
sprintf(t,"%0.1f",illumination);//将光照值加入到t字符串中
strcat(data_send,t);
strcat(data_send,"湿度");
sprintf(t,"%0.1f",humid);//将湿度值加入到t字符串中
strcat(data_send,t);
strcat(data_send,"温度");
sprintf(t,"%0.1f",temperature);//将温度值加入到t字符串中
strcat(data_send,t);
tempfd=write(fd,data_send,strlen(data_send));
break;
case1:
strcpy(data_send,调已关闭");tempfd=write(fd,data_send,strlen(data_send));break;
case2:
strcpy(data_send,"空调已开启");tempfd=write(fd,data_send,strlen(data_send));break;
case3:
strcpy(data_send,"灯已关闭");tempfd=write(fd,data_send,strlen(data_send));break;
case4:
strcpy(data_send,"灯已打开");tempfd=write(fd,data_send,strlen(data_send));break;
case5:
strcpy(data_send,"小车已启动");tempfd=write(fd,data_send,strlen(data_send));break;
case6:
strcpy(data_send,"小车已停止");tempfd=write(fd,data_send,strlen(data_send));break;
}
pthread_mutex_unlock(&glb_va.mutex);
}
if(tempfd==-1){
break;
}
}
printf("停止当前连接.....\n\n");
close(fd);
count_client--;//
pthread_exit(NULL);
}
intmain(void)
{
pthread_tpthid=0;
structsockaddr_ins_addr={0};
structpthread_argptharg[CHPTH_COUNT]={{0}};
/*设置互斥锁,如果第二个参数如果是NULL,表示使用默认设置*/
ret=pthread_mutex_init(&glb_va.mutex,NULL);
if(skfd<0)err_fun(__FILE__,__LINE__,"pthread_mutex_init",ret);
skfd=socket(PF_INET,SOCK_STREAM,0);
if(skfd<0)err_fun(__FILE__,__LINE__,"socket",errno);
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(SER_PORT);
s_addr.sin_addr.s_addr=inet_addr(SER_IP);
ret=bind(skfd,(structsockaddr*)&s_addr,sizeof(s_addr));
if(ret<0)err_fun(__FILE__,__LINE__,"bind",ret);
ret=listen(skfd,MAX_CONNECT);
if(ret<0)err_fun(__FILE__,__LINE__,"listen",errno);
printf("监听客户地址[%s]端口号[%d].\n",SER_IP,SER_PORT);
signal(SIGINT,signal_fun);
while
(1){
printf("\n等待新的连接...\n");
cfd=accept(skfd,NULL,NULL);
if(cfd==-1){
fprintf(stderr,"监听出错!
\n");
continue;
}
if(count_clientprintf("现在已经开始连接客户%d.",count_client+1);
ret=pthread_create(&pthid,NULL,(void*)(&pthread_fun),(void*)(&cfd));
if(ret==-1){
fprintf(stderr,"线程创建错误!
\n");
break;
}
}
}
return0;
}
五、测试数据及其结果分析
开启服务器:
连接一个客户端:
客户端显示界面:
(用户可以输入控制序号)
按下0时服务器收到消息:
按下0时服务器显示车内环境信息:
服务器收到控制序号1:
客户端输入1,并收到服务器信息:
空调已经关闭:
服务器收到序号5:
客户端显示小车已启动
服务器连接第二个客户端时:
第二个客户端下线时,服务器显示:
该客户端退出:
当两个客户端同时向服务器发送消息时,开启的互斥锁使得当前面的信息处理完毕时再处理第二个客户端。
6、调试过程中的问题
1、当两个客户端同时向服务器发送消息时,会同时向服务器端写入,引起混乱。
解决的办法是加入了互斥锁。
开启的互斥锁使得当前面的信息处理完毕时再处理第二个客户端。
2、碰到了一些基本语法错误,比如字符串之间的比较,复制,以及sprintf函数的学习使用将多个数据拼接传输到客户端,通过查阅网络信息得以解决错误。
3、初步传感器的车内环境信息:
温度、光照、湿度是客户端自己生成并显示的,经过改进,将生成的数据置于服务器并发送至客户端,实现真正的模拟传感器收发。
七、参考文献和查阅的资料
上课所用实例代码
八、程序设计总结
这次程序设计,我实现了在linux操作环境下进行一个服务器和多个客户端之间的通信,利用传感器传输小车内的环境信息,利用线程服务多个客户端,用read和write函数实现数据传输。
和同伴的互助之下,完成了这个小程序,并且我深刻感悟,重要的不是编码能力,而是团队协作能力,并且在想法的交流中摩擦出了智慧的火花。