您的当前位置:首页正文

嵌入式系统设计与实现课程设计报告

2022-12-20 来源:客趣旅游网


嵌入式系统设计与实现

课程设计报告

课程名称嵌入式系统设计与实现 班级 学号姓名 指导教师 成绩

自动化学院 2018年7月

1. 课程设计题目

嵌入式linux系统下的局域网聊天软件设计

2. 课程设计内容与成员分工

耿欣宇负责:显示在线用户、群聊、私聊和提示帮助这些功能模块,还负责课设报告的整理。

负责:退出聊天、账户登录(验证名字是否重复)、人满排队、唤醒和TCP通信功能这些功能模块,还负责展示ppt的整理。 两人共同调试两台电脑之间的聊天通信。

3. 课程设计原理 一、客户机/服务器模式

在网络中最常用的通信模式是客户机/服务器模式(Client/Server模式或C/S模式)。服务器方要先启动,并监听指定端口,等待客户端的请求,根据客户端的请求提供相应服务。

多个相互通信的计算机都作为客户端,与网络服务器进行连接,并通过服务器进行信息的传递。所以多个客户端之间的通信就变为了客户端与服务端的通信。所以,采用客户/服务器模型进行网络聊天需要分别编写服务器端和客户端的程序。 二、套接字

Socket实际是网络传输层供给应用层的编程接口。传输层则在网络层的基础上提供进程到进程访问的逻辑通道,而应用层的进程则利用传输层向另一台主机的某一进程通信Socket就是应用层与传输层之间的桥梁。

套接字有三种类型:

数据流套接字(SOCK_STREAM):对应TCP协议。 数据报套接字(SOCK_DGRAM):对应UDP协议。 原始套接字(SOCK_RAW)。通过使用原始套接字,可以将网卡设为混杂模式。

基于 TCP 协议的客户端程序设计步骤如下: Step1:用函数 socket()创建一个 socket; Step2:设置要连接的对方的 IP 地址和端口等属性; Step3:用函数 connect()连接服务器;

Step4:用函数 send()和 recv(),或者 read()和 write()收发数据; Step5:关闭网络连接。

基于 TCP 协议的服务器端程序设计步骤如下: Step1:用函数 socket()创建一个 socket;

Step2:用函数 bind()绑定 IP 地址、端口等信息到 socket 上; Step3:用函数 listen()设置侦听的最大并发连接请求数;

Step4:用函数 accept()接收客户端 Step5:用函数 send()和 recv(),或者 read()和 write()收发数据; Step6:关闭网络连接。

(1)Socket()

作用:socket函数为客户机或服务器创建一个sokcet 格式:int socket(intfamily,inttype,int protocol); 参数说明:

Family:表示地址族,可以去AF_UNLX和AF_INT。

其中,AF_UNLX只能够用于单一的UNIX系统进程间通信;AF_INT是针对Internet的,因而可以允许在远程主机之间通信,实验中使用AF_INT。

Type:网络程序所采用的通信协议,可以取SOCK_STREAM或SOCK_DGRAM。其中,SOCK_STREAM表明使用的是TCP协议,这样提供按顺序的、可靠的、双向、面向连接的比特流;SOCKE_DGRAM表明使用的是UDP协议,这样只会提供定长、不可靠、无连接的通信。 (2)bind( )

格式:int bind(intsockfd,structsockaddr *addr,intaddrlen); 参数说明:

Sockfd:socket的文件描述符号。

Sockaddr:表示名字所用的一个数据结构,用来保存地址(包括IP地址和端口)。 Addrlen:设置结构大小长度。 (3) listen()

格式:int listen(intsockfd, int backlog); 作用:监听连接信号,和accepted函数合同。 参数说明:

Sockfd:表示socket调用返回的文件描述符。

Backlog:表示接入队列允许的连接数目,大多数系统允许20个,也可以子定义5~10个。 (4) accept()

格式:Int accept (intsockfd, void *addr, int *addrlen)。 作用:与listen函数合用,监听信息、接收客户端请求。 参数说明:

Sockfd:表示socket的文件描述符。

Addr:表示指向局部的数据结构structsockaddr-in的指针。 Addrlen:表示地址的长度。 (5) connect()

格式:int connect( intsockfd , structsockaddr *serv_addr , intaddrlen)。 作用:在面向连接的系统中客户及连接服务器时使用,connect必须在bind后使用。 参数作用:

Sockfd:表示socket的文件描述符。

Serv-addr:表示村访目的端口和ip地址(套接字)的数据结构。 (6) send() 和recv()

格式1:Int send (intsockfd, constvod *msg,intlen, int flags)。 功能:发送信息。

格式2:Intrecv (intsockfd , void *buf,intlen, usignedint flags)。 作用:用于流式socket、数据报socket内部之间的通信。 (7) close( )

格式: Close( intsockfd)。

3. 课程设计步骤 一、群聊功能模块

二、私聊功能模块

三、显示在线用户功能模块

四、提示帮助功能模块

登录模块、人满排队模块、退出模块、唤醒模块流程图:

五、登录功能

首先是服务端和客户端分别启动运行,当argc=2,(输入了IP地址且客户端运行正常后),在void *pthread_fun中将FLAGE设置为1,提示通讯通道开启。

再在主函数中执行FLAGE=1时的程序:客户端进行判断是否已有3人在群中,若小于3,则利用scanf进行用户名的录入。并利用send函数将用户名发送到服务器中,进而再服务器中利用intlogform及cmpname进行名字的辨别。

若命名重复(已存在)提示创建错误,而后在客户端中的条件判断会被激活,利用strncmp进行检测

进而,FLAGE=3中会给用户3次机会进行重新命名,超过三次则自动退出。若命名不重复,则会打印其已上线。

六、人满排队

在服务器pthread_rwlock_rdlock中会不停的接收客户端发来的连接请求,在客户端人数到达3时,idx会被赋值-1。

同时在void pthread_fun中会在缓存区存入sprintf(buf, \"NOTICE\\r\\n服务器已满,请等候\\r\\n\\r\\n\");之后客户端的条件判断再次被激活,用户的信息会被存储在服务器缓存区。

在客户端满足FLAGE=0会不断刷新并每隔一秒打印一次“服务器已满,请等待”的提示语。

七、退出功能

主要利用的是close(fd)结束通信来实现。当用户客户端输入quit后,条件判断else if(!strcmp(str,\"quit\"))被激活,客户端执行fun_quit函数,进而将

QUIT存入缓存区,并利用send将其发送至服务器,再服务器中条件判断再次被激活if (!strncmp(buf, \"QUIT\\r\\n\\r\\n\8)),进而客户端执行quit()函数,利用close结束通信,并将退出的提示存入缓存区再发送到客户端,所有在群的人都可以看到此人退群的提示。

八、唤醒功能

此功能主要是有人退出聊天室且有人在等待(想加入群聊却群聊人满未加入处于等待)的情况下,会被唤醒,即可以进入群聊。在quit函数中会不停判断if(head != NULL && head->next != NULL)即判断是否有人在等待,不为空即有人等待的情况下,利用互斥锁去调用idx = find_fd(client);在利用缓存区和send在客户端提示加入群聊,并在存储区内利用free()释放这个位置。

九、TCP主体搭建

server端,server首先启动,调用socket( )创建套接字;然后调用bind( ) 绑定server的地址(IP+port);再调用listen( )让server做好侦听准备,并规定好请求队列长度,然后server进入阻塞状态,等待client的连接请求;最后通过accept( )来接收连接请求,并获得client的地址。当accpet接收到一个client发来的connet请求时,将生成一个新的socket,用于传输数据。

client端,client在创建套接字并指定client的socket地址,然后就调用connect( )和server建立连接。一旦连接建立成功,client和server之间就可以通过调用recv和send来接收和发送数据。一旦数据传输结束,server和client通过调用close( )来关闭套接字。

5. 软件使用说明 一、启动服务器

二、账户登录(同时具有重名检测功能)

三、帮助提示(输入help可查看主要功能表)

四、显示在线用户

五、私聊

六、群聊()

七、退出聊天

八、人满排队

九、唤醒

6. 遇到的问题及解决办法

一、在启动服务器之后,再启动客户端,第一个人连接127.0.0.1的本地回环地址。如果第二个人继续连接127.0.0.1这个本地回环地址,他的客户端就不能正常启动。之后我们通过试验发现每启动一个客户端就要为其单独分配一个本地回环地址(比如第一个人使用127.0.0.1,第二个人使用127.0.0.2,以此类推),这样才能保证每个人的客户端都能正常运行。

二、我们在修改程序时有时只改了客户端或者只改了服务器端的中文提示符,之后就出现了客户端和服务器端不能正常通信的情况,如果两端都修改成统一的字符就又能正常运行了,之后发现是程序里strncmp函数要将服务器端传来的字符与客户端的字符进行比较,如相同才能往下运行,如不同就停止、退出了。 三、我们在进行两个电脑之间调试时,两个电脑之间互相pingIP地址可以ping通,服务器和客户端程序在同一个电脑上用本地回环地址也可以正常运行,但就是在两台电脑上一个运行客户端、另一个运行服务器端程序就只执行了一部分,通信构建成功了,但是无法正常启动客户端,导致无法聊天。我们猜测是因为两台电脑导致程序的一致性被破坏了,客户端所传回的内容与服务器端的内容不同。strncmp函数检测到不同,就停止运行程序退出了。

7. 心得体会

:本次嵌入式课设让我有机会真正的接触嵌入式应用的开发。从一开始看到很多代码的不解与急躁,到之后一行一行的去看,去查询代码中每一个不知道的函数的用法及例子,直至搞懂每一行;每一段;每一个功能模块的实现方式。再到之后能自主修改代码中不合理的地方,并自主的添加一些功能,使整个聊天软件的功能和汉化变的全面与合理。通过这些让我的嵌入式开发水平得到了很大的提升,不再像原来的实验课一样,每回只实现一个很小的功能,而是要将原来分散实现的功能汇聚在一起进而实现一个更强大的功能。这中间确实也遇到了很多没见过的知识点与问题,绝大多数的问题我通过学习与询问他人都解决了,但也有的问题我们没能解决,比如说我们的程序在一台电脑上使用本地回环地址就能运行,但在两台能够互相ping通的电脑上就不能运行这个问题。我进行了无数次的问题猜测与相关尝试仍没能解决,这个问题至今也还在困扰着我,可谓是我们这次课设的一个遗憾,但我会记住这个问题,争取在以后的工作、学习生活中找到相关的解决方法。本次嵌入式课设更像一个启蒙老师,带我们了解、走进嵌入式开发,让我们有机会将嵌入式课程上的知识实际利用起来,并结合实际丰富理论知识上的不足,我想这就是我们这次嵌入式课设的主要意义吧。

:大三下学期中,我们学习了嵌入式系统课程配以实验课,结课一个月后暑假小学期完成了嵌入式课程设计。我们制作了linux聊天室,感触颇丰。我先阅读老师给提供的程序范例去理解这个范例的思路,发现自己对理论知识有遗忘,比如tcp传输协议、套接字等。阅读例程后,我俩分功能模块先独立制作。为了更好的把控各子模块关系,我先绘制了我所负责全部功能模块的流程图构思。我负责主体搭建,因为TCP协议具有数据的可靠性、应用的实时性、网络的可靠性三个优点,我选择TCP协议编写服务器端程序和客户端程序。最终实现了客户、服务器之间的连接和通信。我先利用socket、bind、listen建立连接,客户端发送请求(包括初始化socket端口、利用connect函数将自己的IP地址等信息发送到主机),服务器通过accept接收请求。整个通信过程中,服务器线程一直处于休眠状态,直到有一个客户对这个服务提出了连接请求,此时服务线程被“唤醒”并为客户提供服务。此外我制作了登录(包括重名验证、人多排队)及退出、唤

醒(有人退出后可加入群聊)的相应功能。我利用结构体存储链接客户的信息,以链表式来记录链接客户。此外,我选用了读写锁作为线程的同步机制。其分为三种状态:读模式下的加锁,写模式下的加锁,不加锁。当某个线程读操作时,其他线程允许读操作,不允许写操作;当某个线程写操作时,其它线程都不允许读或写操作。因为聊天过程中的登录、私聊、群发等功能要频繁进行数据修改,所以选用了读写锁可大大提高效率。在任一时刻允许多个读出者存在,提高了并发度,在某个写入者修改数据期间保护该数据,以免任何其它读出者或写入者的干扰。完成我自己的模块后,我书写了相关的功能模块实现介绍,产生了小小的成就感。而后我们进行了各模块汇总及调试,最终实现了初期计划的全部功能,感觉很开心!课程设计不同于理论课,我们真正的去实践这样一个小的项目。利用百度查阅资料,图书馆借阅书籍,通过这个课程设计锻炼了我的自学能力!

因篇幅问题不能全部显示,请点此查看更多更全内容