APP下载

基于Linux的FTP服务器设计

2022-11-16陈丽琼

无线互联科技 2022年3期
关键词:会话线程队列

朱 澳,陈丽琼

(湖南科技学院 智能制造学院,湖南 永州 425199)

1 背景及意义

Windows系统上的FTP服务器软件虽然种类很多,但是大部分都是需要付费使用的,许多软件就算付费也有许多问题存在。而在Linux上,利用shell命令使用FTP服务器,能让FTP的使用极为方便简洁。在Linux上,它们是可以完全免费使用的,比如vsftpd。开发一个基于Linux的FTP服务器具有重要的意义[1]。

2 需求分析

本FTP服务器的主要模块包括登录模块、文件目录操作模块、文件操作模块、文件传输模块、工作模式和下载模块。登录模块包括本地用户直接登录和用户匿名登录两种方式。匿名用户登录时应注意控制在当前目录下,但只有在客户端才能出现在根目录下。登录用户模式下的用户名必须是在Linux环境下运行的用户,如果不是Linux环境下运行的用户,登录时会提示出错。原因是这种登录模型的前提是让Linux用户判断用户名和登录密码的一致性和正确性。一些基本的目录操作都是由文件目录操作模块来完成的。一般来说,文件目录操作模块包含了对目录的删除、目录的重命名、特殊情况下的增加目录操作等。以上所有的操作都必须是Linux用户,如果是一个匿名用户将无法进行上述操作[2]。其他与文件相关的操作一般同上述的目录操作一起进行,比如对文件进行删除和重命名等。只要是用户在客户端进行的操作,都是属于混合操作,那么客户端的处理方式是将所有的这些混合操作转化成命令传输到服务器端。用户要实现文件上传或将文件下载到本地都需要使用文件传输模块来实现。其中还有很重要的一个功能是断点续传。当然,文件上传和下载才是本文设计的服务器的最主要功能,也是同断点续传一样有用的功能[3]。

3 总体设计

程序开始执行时,从配置文件中读取相关的内容进行初始化,如使用的连接方式、监听的端口、监听的服务器IP地址、支持连接的总IP数量等。然后,通过创建一个守护进程来避免一些问题的出现,比如关于进程暂停的问题。创建一个守护进程主要是进行初始化操作,该操作主要是通过应用共享内存来实现。这里的处理既包括数据进程的建立,也包括对进程函数的调用。最后利用TCP协议创建Socket套接字来进行监听,服务器接收客户端并创建新的套接字。此过程需要创建一个子进程来处理通信服务[4]。

4 FTP服务器的实现

4.1 进程的启动

基于epoll、半同步/半异步模型以及线程池的FTP服务器是采用配置文件的方式保存系统配置以及用户信息的。该用户信息包括用户名、密码、权限、工作目录、日志文件等。服务器支持PASV被动打开方式进行数据传输,支持断点续传与多用户不同权限接入控制。线程池采用动态创建与回收基制,其中线程池保存两个队列——工作线程队列与空闲线程队列。当空闲队列中线程数低于一个门限或高于一个门限时,则分配或回收一部分线程,从而在保证系统高效性的前提下尽可能减小系统开销。

整个系统的工作流程如下,系统启动后首先进行资源分配,读入配置文件,初始化线程池,初始化 epoll模型并开启监听;当新用户接入时,进行用户接入验证,若合法则允许接入并把用户消息保存到用户管理对象中;当新命令到达时,把命令放入消息队列中等待处理;系统开启若干个线程用来处理消息队列中的消息,并使用信号进行通知,一旦消息队列非空时,则会唤醒一个空闲线程;当读到“LIST”“STOR”“RETR”“REST”时,说明用户准备进行数据传输,则在数据传输线程池中提取一个空闲线程,修改线程数据并放到工作线程中执行,执行完毕后由线程把结果状态返回给用户并从工作状态进入空闲状态。用户自接入成功一直处于命令交互状态,直到发送“QUIT”退出。

4.2 守护进程的实现

首先,设计人员应该打开任务管理器,查看一下正在运行的有哪些进程。然后,逐一读取出这些进程的全路径,将该全路径与要守护的应用程序的全路径比对。如果一致,说明要守护的应用程序已开启了,此时要分配一条线程监控该进程句柄。当该进程句柄返回信息,说明该进程已关闭,此时释放进程句柄内存,并重启该进程。如果遍历任务管理进程列表中所有进程时,没有找到与要守护的应用程序的全路径一致的进程,说明要守护的应用程序尚未打开,此时要启动该应用程序,然后转入监控流程。另外,一定要额外分配线程去监控要守护的应用程序。因为如果、使用主线程去执行监控任务,会被长期阻塞,直到进程退出才会被激活,这样就无法运行后续程序。况且,监控程序要实现持续监控,必须避免死循环,如果主线程进入死循环,则无法监控其他要守护的进程。创建守护进程的关键步骤如下。

4.2.1 后台实现

一般情况下,在后台实现的第一步需要让父进程重新排队,而子进程由用户进行创建。注意这时的父进程称为一个孤儿进程。而在守护进程的终端,第一步将完成在shell终端的运行。设计人员要守护进程在后台实现,就必须让守护进程不被挂起,采用的方法是调用fork()函数让父进程结束,这样守护进程就会作为子进程在后台运行。

4.2.2 登录会话和进程组

虽然守护可以在后台运行,但是调用fork()函数后产生的子进程所拥有的资源是继承父进程而来的,包括进程组、登录会话、控制终端的这些资源是可以被系统收回的。为了能够让守护进程不受控制,设计人员可以通过调用setsid()函数实现。setsid()函数的主要功能就是使进程成为新的进程组长和会话组长,这样就能够同从父进程那边继承下来的登录会话和进程组真正脱离。

进程组也被称为作业,这个作业本质上是由一个或多个进程组合而成,这是进程组的一个重要特征。进程组中有多个进程,每一个进程不是孤立存在的,一定是属于某一个确定的进程组。在waitpid函数和kill函数的参数中都曾使用进程组的概念,目的是简化对多个进程的管理。当父进程创建子进程时默认子进程与父进程属于同一个进程组,进程组ID等于进程组第一个进程ID(组长进程)。所以,组长进程标识其进程组ID。组长进程可以创建一个进程组及进程组中的进程,也可以随时被终止。只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关。

会话期间通常包含了至少一个进程的集合。既然是会话,前提是用户一开始就进行了登录操作,而且一定要成功登录,当用户退出登录以后回话结束。在整个过程中,出现的所有进程都是在当前的会话中,也隶属于当前的会话。

4.2.3 禁止程序重新开启控制终端

禁止程序重新开启控制终端,是服务器端需要严格考虑的问题,以保证整个服务器的运行正常。现在,进程已经成为无终端的会话组长,但它可以重新申请打开一个控制终端。要禁止进程重新打开控制终端,采用的方法是再次创建一个子进程,使进程不再成为会话组长。

4.3 关闭打开的文件描述符

守护进程的实现过程中,有一个标准步骤是关闭当前打开的所有文件描述符。当lim.rlim_curr为RLIM_INFINITY时,只需要关闭前1 024个文件描述符。遍历所有可能打开的文件描述符是比较复杂的。但现在的系统调用很快,很多系统调用不用耗费太长的时间即可完成。通常情况下,守护进程启动的时候,打开的文件描述符不多。

5 结语

各大高校为师生提供了一些基本的网络服务,比如教师和学生可以通过教务系统进行成绩、选课和评教方面的操作,还能够共享一些软件安装文件。教师也建设了自己的一些课程网站。通过课程网站,教师可以提供教学资源供学生浏览和下载,也可以发布最新的科研成果;学生能够通过这些网站满足一定的文件下载和共享需求。随着双一流精品课程的建设,师生在使用过程中可能受到网速的限制,不能及时下载和上传。为了让这些网站真正发挥作用,本文设计并实现了一个基于Linux的FTP服务器,供教师和学生访问。

猜你喜欢

会话线程队列
队列里的小秘密
在队列里
丰田加速驶入自动驾驶队列
有意冒犯性言语的会话含义分析
浅谈linux多线程协作
汉语教材中的会话结构特征及其语用功能呈现——基于85个会话片段的个案研究
冲突语的会话分析研究
对外汉语课堂英语通用语的会话调整功能
基于上下文定界的Fork/Join并行性的并发程序可达性分析*
Linux线程实现技术研究