毕业设计反思

毕业设计的代码基本完成,编程能力还有待提高,现在总结一下。

功能简介:由于发现arm板和PC机(虚拟机的linux系统)传输文件比较不便利,所以任务就是实现linux和arm版的文件传输,包括界面和网络两部分


第一个问题:

客户端架构:对于架构,吃了不少苦头(毕竟自己还是菜鸟)。开始就是直接网络代码和界面代码没有分的很开,当界面发送文件按钮一按下,对应的触发函数调用网络发送函数。这导致了两个问题。一个就是进度条和进度数值无法在文件发送或者接收过程更新(原因就是界面和网络代码可以说在一个线程里,虽然界面更新使用定时器,但是在文件读写过程中,暂时无法触发了)。第二个问题,当忽略某种情况时候,修改代码起来,改动过大。例如忽略服务端如果存在相同文件的情况,这除了要修改代码使得显示小窗口提示是否覆盖,还要修改网络代码支持是否覆盖服务端的文件,这还是有点麻烦。

改进的做法就是把界面代码和网络代码分开,客户端主函数创建两个函数,一个处理界面问题,一个处理网络问题,通过一个结构体实现两者间的信息通信:

	init_MainBridge(&mainbridge);

	if(pthread_create(>k_tid,NULL,gui_main,&mainbridge) !=0)
	{
		My_Debug("%s %d:can not create gtk pthread\n");
	}

	if(pthread_create(&client_tid,NULL,client_main,&mainbridge) !=0)
        {
                My_Debug("%s %d:can not create client pthread\n");
        }
client_main就是客户端的网络代码,而gui_main就是处理界面 代码,包括主界面和小界面。这个做法解决的问题,一个就是进度条和进度标签更新,因为此时进度条和进度标签更新和文件发送和接收过程是在两个不同线程,用mainbridge结构体来进行联系。

客户端效果图:


而服务端的架构就比较简单:

struct serverDoRequist{
	reqType    	CmdType;          //客户端命令
	int (* func)(int fd);				//命令处理函数
}serverDoRequistType[]=
	{
		{REQ_NONE,NULL},
		{REQ_SEND,server_recieve_noexit_file},
		{REQ_FORCE_SEND,server_recieve_canexit_file},
		{REQ_RECV,server_send_file}	
	};
void process(int connfd)
{
	char message[PKG_SIZE_ALL];
	struct serverDoRequist *aRequist;
	for(;;)
	{
		if(receive_message(connfd,message)<0)
		{
			My_Debug("%s %d:ignore  message\n",__FUNCTION__,__LINE__);
			break;
		}
		if((aRequist = parse_message(message))==NULL)
		{
			My_Debug("%s %d:parse message err\n",__FUNCTION__,__LINE__);
			send_reply_message(connfd,message,NULL,REPLY_FAIL);
			continue;
		}
		send_reply_message(connfd,message,REPLY_SUCCESS);

		aRequist -> func(connfd);	
	}

第二个问题:

此次还有用到很多小型窗口:

正确窗口,例如:


还有失败窗口,例如:

                                                                        

选择窗口,例如:    

                                                                                                                                      


首先不可能为每一个小窗口都写一个函数的,所以我使用了miniWind函数来实现所有的小窗口,代码如下:

#include "gui.h"
#include "gui_set.h"

static void selectNo_event(GtkWidget *widget,gpointer data )
{
        gint  *selectResult = (gint *)data;
        *selectResult = SELECTBUTTON_NO;
        gtk_main_quit();
}
static void selectYes_event(GtkWidget *widget,gpointer data )
{
        gint  *selectResult = (gint *)data;
        *selectResult = SELECTBUTTON_YES;
        gtk_main_quit();
}

static gint delete_event(GtkWidget *widget,GdkEvent *event,gpointer data)
{
        gtk_main_quit();
        return FALSE;
}

/*select and err window*/
/*return value about select window
*Yes:1;No:0
*/
int miniWind(const char *printStr,MiniWind mwIndex)
{
	GtkWidget	*miniwindow;
	GtkWidget       *errLabel;
	GtkWidget       *sureButton;
	GtkWidget       *yesButton;
	GtkWidget       *noButton;
	GtkWidget	*table;
	gint		selectResult;
/*set miniwindow*/
	miniwindow = gtk_window_new(GTK_WINDOW_POPUP);
	 gtk_window_set_position (GTK_WINDOW(miniwindow),GTK_WIN_POS_CENTER);
        gtk_window_set_default_size(GTK_WINDOW(miniwindow),200,100);
/*add table to miniwindow*/
	table = gtk_table_new(3,3,TRUE);
        gtk_container_add(GTK_CONTAINER(miniwindow),table);
/*add label to table*/
	if(printStr!=NULL)
	{
		errLabel = gtk_label_new (NULL);
        	set_label_markup(GTK_LABEL (errLabel),printStr);
        	gtk_table_attach_defaults(GTK_TABLE(table),errLabel,0,3,0,2);
	}
/*add sure button to table*/	
	 if((mwIndex == ERRWIND) || (mwIndex == SUCCESSWIND))
        {
                if(mwIndex == ERRWIND)
                        fill_image_for_widget(miniwindow,"./pic/errWind.png");
                else
                        fill_image_for_widget(miniwindow,"./pic/successWind.png");

		sureButton = gtk_button_new_with_label("确定");
		gtk_table_attach_defaults(GTK_TABLE(table),sureButton,1,2,2,3);
		g_signal_connect(G_OBJECT(sureButton),"clicked",
                	G_CALLBACK(delete_event),NULL);
	}
        if(mwIndex == SELECTWIND)
        {
		fill_image_for_widget(miniwindow,"./pic/warnWind.png");
                yesButton = gtk_button_new_with_label("Yes");
                gtk_table_attach_defaults(GTK_TABLE(table),yesButton,0,1,2,3);
                g_signal_connect(G_OBJECT(yesButton),"clicked",
                        G_CALLBACK(selectYes_event),&selectResult);
                noButton = gtk_button_new_with_label("No");
                gtk_table_attach_defaults(GTK_TABLE(table),noButton,2,3,2,3);
                g_signal_connect(G_OBJECT(noButton),"clicked",
                        G_CALLBACK(selectNo_event),&selectResult);

        }

        gtk_widget_show_all(miniwindow);
        gtk_main();
	gtk_widget_destroy(miniwindow);
	return selectResult;
}

第三个问题:

文件的传输过程也花了我不少时间。一个就是如何发送和接受一个文件。我的最终的做法:

发送:

1、客户端发送请求(发送文件),等待服务端反馈。

2、如果反馈成功,那么客户端发送文件名,等待服务端的反馈包。

3、若反馈成功,客户端就发送文件长度给服务端(需要文件的长度原因有三:需要更新进度条、发送方可以判断文件是否读完,接收方可以判断是否接收完毕),等待服务端的反馈。

4、若反馈成功就发送文件内容,发送完毕,等待服务端服务端的反馈包。

接收:

1、客户端发送请求(接收文件),等待服务端反馈。

2、如果反馈成功,那么客户端发送待接收的文件名,等待服务端的反馈包。

3、若反馈成功,客户端就接收服务端发来的待接收文件长度(原因有三和发送类同),发送反馈包给服务端。

4、客户端接收文件内容,接收完毕,发送反馈包给服务端。

所谓的反馈包实际就是确认包。例如,客户端发送给服务端文件名字,服务端反馈包就说明服务端已经存在该文件了,是否还有继续。又例如,待发送的文件,服务端根本没有这个文件存在,反馈错误。


所以对于这个操作过程,采取的就是传输的数据都是一个个数据包。每一个数据包,都包含包头和包数据,其中包头表明这个是反馈包还是请求包还是数据包,若是请求包,包头要区分是发送还是接收,数据包(包括文件名还是文件内容)和反馈包(成功还是失败还是出错类型)。包数据存放的就是有效数据部分,例如文件名或者文件内容(刚开始还包括服务端反馈的额出错信息,例如文件已经存在,后来发现会增加复杂度就舍弃了)。

#define  PKG_SIZE_HEAD				4  //包头大小
#define  PKG_TYPE				0 //包头第一个字节表示包数据的格式
#define  PKG_LEN_L				1//包头第二、三个字节表示包的总长度	
#define  PKG_LEN_H				2
#define  PKG_TYPE_CLASSIFY                      3  //包头第四个字节,是数据格式的分类
#define  PKG__SIZE_VADATA			(1000)  //包有效数据大小
#define  PKG_SIZE_ALL				(PKG_SIZE_HEAD+PKG__SIZE_VADATA)
/*包数据的格式*/
ttypedef enum pkg_type{TYPE_NONE,TYPE_REQ,TYPE_DATA,TYPE_REPLY,TYPE_END} pkgType;

/*类型分类*/
typedef enum classify_req{REQ_NONE,REQ_SEND,REQ_FORCE_SEND,REQ_RECV} reqType;
typedef enum classify_data{DATA_NONE,DATA_FILENAME,DATA_FILELEN,DATA_FILECONTENT}dataType;
typedef enum classify_reply{REPLY_NONE,REPLY_SUCCESS,REPLY_FAIL,REPLY_FILEEXIT,REPLY_FILENOEXIT}  replyType;


/*以下宏定义实现对包头的一些设置工作*/
#define PVAL(buf,pos,type) (*((type *)(buf + pos))) 
#define CVAL(buf,pos) PVAL(buf,pos,unsigned  char) //读取包头的第pos位字节数值
#define SCVAL(buf,pos,x) PVAL(buf,pos,unsigned char) = (x)//对包头的第pos位字节设置为x
//设置传输包的头
#define messageHead_set(pkgType,classifyType,len,message)   {\
		SCVAL(message, PKG_TYPE,pkgType);		\
		SCVAL(message,PKG_TYPE_CLASSIFY,classifyType); \
		SCVAL(message, PKG_LEN_L,(len%256));	\
		SCVAL(message, PKG_LEN_H,(len/256));		\
	}
//得到传输包
#define messageHead_get(pkgType,classifyType,len,message)   {	\
		pkgType 	= CVAL(message, PKG_FLAG_DATA);		\
		classifyType	= CVAL(MESSAGE,PKG_TYPE_CLASSIFY);	\
		len		= CVAL(message, PKG_LEN_L)|CVAL(message, PKG_LEN_H)<<8;	\
	}


经常有人说“一个函数实现一个功能”,这次还是蛮有体会,一方面在于如果函数的书写不够好,会导致你修改代码越修改到后面也难修改,并且如果不重构,函数功能会越混乱。再者就是服务端和客户端有很多相似代码,例如发送和接收文件两方都需要,所以需要提取共用函数。这也方便调试BUG,调试BUG的过程要远大于自己书写代码的过程(关键部分的出错信息打印也是调试BUG总要部分



最后一个问题

一个东西做出来,从使用上说要别人很容易就会使用;从代码上上来看,除了易读外也要容易扩展功能。界面的好处可以让别人容易使用,但是经常要依赖一些库,没有库就用不了,这样从方便使用者角度来说就得不偿失,所以如果为了便于使用,并且功能又那么简单,觉得还是不要用界面,这样使得代码不易移植。

我的毕设硬性要求需要界面支持,我选择的是GTK,GTK对于linux系统来说,系统可选择性自带,这样就不用装得那么麻烦,再者就是GTK是使用C语言编写。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
摘要…………………………………………………………………………………I 目录…………………………………………………………………………………I 1.绪论………………………………………………………………………………1 1.1项目背景及意义……………………………………………………………2 1.2国内外研究现状……………………………………………………………3 2.IT运维系统上的运用……………………………………………………………3 2.1传统IT运维服务系统与云架构的运维服务系统对比……………………4 2.2基于云架构的运维服务系统的技术特点…………………………………4 2.3基于云计算的运维服务系统的云架构模型设计…………………………4 3.需求分析……………………………………………………………………………5 3.1设计原则与目标……………………………………………………………5 3.2功能需求……………………………………………………………………5 3.3安全需求……………………………………………………………………5 4.基于云平台IT运维服务系统的设计……………………………………………7 4.1系统架构设计………………………………………………………………8 4.2系统云架构平台设计………………………………………………………8 4.3系统应用架构设计…………………………………………………………9 4.4系统模块设计………………………………………………………………9 5.基于云平台IT运维服务系统的实现……………………………………………10 5.1系统实验环境……………………………………………………………11 5.2系统功能实现……………………………………………………………12 6.结论与展望………………………………………………………………………13 6.1论文工作总结……………………………………………………………14 参考文献……………………………………………………………………………16
### 回答1: 毕业设计技术路线的具体选择需要考虑多种因素,例如选题的领域、目标、时间、资源等。一般来说,技术路线的选择应该基于对目标的全面分析和研究,包括但不限于以下几个方面: 1. 领域研究:针对选题所属的领域,进行调研和分析,了解前沿技术和研究方向。 2. 数据采集:根据选题要求,收集相关数据,包括结构化数据、非结构化数据、实验数据等。 3. 数据处理:对采集到的数据进行清洗、筛选、去噪、特征提取等处理,获取可用于分析和建模的数据集。 4. 模型选择:基于选题要求和数据集特点,选择适合的建模方法和算法,例如机器学习、深度学习、神经网络等。 5. 模型优化:对模型进行调参和优化,以提高模型的准确性、鲁棒性和泛化能力等。 6. 结果分析:对模型的结果进行统计和分析,评估模型的性能和可行性。 7. 结果呈现:将研究结果以报告、论文、演示等形式呈现出来,向相关人员进行阐述和展示。 总之,毕业设计技术路线的选择需要综合考虑多种因素,以确保选题的研究目标能够得到达成,并且能够满足实际应用的需求。 ### 回答2: 毕业设计技术路线是指在毕业设计中所采取的技术手段和步骤。一般而言,毕业设计技术路线应包括以下几个方面: 首先,需要明确设计的目标和需求。在确定毕业设计题目后,需要明确设计要达到的目标和需求,包括设计的功能、性能、可靠性等方面。这一步骤为后续的技术选型和路线规划提供了明确的方向。 其次,进行技术调研和选型。在确定了设计目标和需求后,需要根据实际情况进行技术调研和选型,选择适合的技术方案。这包括了硬件平台的选择、软件开发工具的选择等。 然后,制定详细的设计方案。在技术选型完成后,需要根据选定的技术方案制定详细的设计方案,包括各个模块的功能划分、接口定义、数据流程等。设计方案需要充分考虑设计的可行性和可实现性。 接下来,进行具体的实施和开发。在制定了详细的设计方案后,需要进行具体的实施和开发工作。这包括硬件的搭建和调试、软件的编写和调试等。实施和开发过程中需要注意测试和调试环节,确保设计的正确性和有效性。 最后,进行系统测试和优化。完成实施和开发后,需要对设计的系统进行全面的测试,包括功能测试、性能测试等。根据测试结果,进行相应的优化和改进,确保设计的稳定性和性能。 综上所述,毕业设计技术路线是一系列的步骤和过程,包括目标与需求确定、技术调研与选型、详细设计、实施开发、系统测试与优化等。它是完成毕业设计的重要指南,能够帮助提高设计的质量和效率。 ### 回答3: 毕业设计的技术路线是指完成毕业设计所需的具体技术步骤和方法。其主要涉及研究内容的选择、实施方案的设计、实验数据的采集和处理、结果的分析和总结等方面。 首先,在选择研究内容时,需要明确专业领域的研究方向和具体的问题,以确保研究具有一定的学术意义和创新性。可以通过文献调研和专家访谈等方法,确定研究的目标和范围。 其次,设计实施方案是非常重要的一步。根据研究目标和问题,制定合理的实验计划和操作流程。选择适当的研究方法和工具,进行实验数据的采集和记录,如实验设备和软件等。 然后,对采集到的实验数据进行处理和分析,运用统计学和相关的数据处理工具,如SPSS、Matlab等,对实验结果进行可视化展示,并进行深入挖掘和解读,得出科学和准确的结论。 最后,通过数据分析和实验结果的总结,对整个毕业设计的研究进行评估和反思,发现存在的问题和不足,并提出改进和扩展的建议。 总之,毕业设计的技术路线是根据研究目标和问题,依次进行研究内容选择、实施方案设计、实验数据采集和处理、结果分析和总结等步骤,通过科学的研究方法和工具,得出有价值和可行性的研究成果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值