c++实现ftp服务器_第三步,尝试用树莓派搭建你的云计算平台和服务器

学完前两步,最后让我们用网页调用你刚刚设计好的内容,进行扩展部分云计算平台的搭建!简单的来说分为以下几点:

1,通过网页访问rcS文件设置开发板IP,避免重启后服务器IP访问失效。然后通过TCP传输协议实现文件的传输。

2,实现嵌入式云计算平台的搭建,可试树莓派、arm开发板等。

3,将复杂运算集中在服务器端,客户端作为接收数据的载体,将数据发送到服务器完成运算后只需要接受结果即可,大大降低了客户端的计算压力。

4,实例演示的一个简单的四则运算,加减乘除,向服务器发送add 4 5,即可返回the result is 9。

移植web_server

开发板中移植web服务器,我选择的是Boa,因为Boa是一种非常小巧的Web服务器,其可执行代码只有大约60KB左右。作为一种单任务Web服务器,Boa只能依次完成用户的请求,而不会fork出新的进程来处理并发连接请求。但Boa支持CGI,能够为CGI程序fork出一个进程来执行。Boa的设计目标是速度和安全。

Boa移植的过程较简单,文章里就不一一描述了,详细过程可以点击“阅读原文”查看,但提醒大家在移植的过程中注意修改文src/compat.h、src/log.c、src/boa.c,否则会出现一堆错误。

网络访问页面配置

通过移植Boa后,我们就可以手动把网页文件index.html拷入到/www目录下,在浏览器输入IP地址即可看到对应网页。但重启开发板之后,需要重新配置IP才可访问网页。如果我们想要重新通过固定IP访问网页,接下来就需要配置IP,netmask,gateway。

在浏览器看到对应三个输入框,输入对应IP,Netmask,Gateway之后,发送到对应的cgi程序处理,后面会对cgi具体内容做介绍。

rcS文件配置:

rcS文件是开发板启动后自动执行的脚本文件,用户可以在里面添加自定义的一些配置。

这里我通过cgi程序修改rcS文件,而rcS文件里面保存由网络页面输入的IP,netmask,gateway配置。

ifconfig eth0 192.168.100.102 netmask 255.255.255.0route add default gw 192.168.100.101

cgi程序设计:

用c语言设计了一个cgi程序,接收网页发来的数据,并完成对应的操作。

(加部分程序,在程序里查看原文)

printf("%s%c%c\n", "Content‐Type:text/html;charset=iso‐8859‐1", 13,10);printf("IP Configuration\n");printf("

IP Configuration

\n");data = getenv("QUERY_STRING");if(data == NULL)printf("

ERROR:no input setup or transmission meet with troubles!"

);else if(sscanf(data, "address=%[0‐9,.]&netmask=%[0‐9,.]&gateway=%[0‐9,.]", address, netmask, gateway)!=3)printf("

ERROR:input is invalid!"

);else{printf("%s%c%c\n", "Content‐Type:text/plain;charset=iso‐8859‐1",13,10);strcat(strcat(strcat(strcat(strcpy(line0, str0), address), str1), netmask), tab);// 原文里包含所有代码

前面块中数据发送的方式是"GET",这里我们通过:getenv("QUERY_STRING")来去接受数据并放在地址data上。通过sscanf函数完成数据的分配。之后打开文件,写入对应行,即可完成IP配置的操作。在sscanf函数里面,可能会注意到%[0-9,.]这种不同于传统%s,%d的数据模式。这是因为特殊字符会经过URL编码,会带来数据接受的错误,而上述模式可以解决这个问题。

页面设置文件传输功能

在开发板移植了FTP程序,然后在主机安装vsftpd程序,在主机打开vcstpd程序,然后在通过页面选择开发板上输入主机的IP地址,是上传还是下载文件,输入文件的名字即可通过TCP协议完成文件的传输。

首先,网络页面配置

<form action="/cgi‐bin/ftp.cgi" method="GET" target="nm_iframe"><p>please input address, transmission type, file pathp><label>IP Address:<input name="address" size="30" maxlength="40">label><br><label>Transmission Type:<input type="radio" name="trans_type" value="download">Downloa<br><input type="radio" name="trans_type" value="upload">Uploadlabel><br><label>File Path:<input name="file_path">label><br><input type="SUBMIT" value="Send">form>

其次,在开发板上安装ftp

使用busybox制作的根文件系统,没有ftp客户端工具,无法登录到其他的ftp服务器,需要自己编译ftp指令。ftp客户端我选择的是netkitftp0.17.tar.gz。(安装过程见“阅读原文”)

再次,在主机上安装vsftpd

安装并启动vsftpd:

sudo apt‐get install vsftpdservice vsftpd start

最后,shell脚本编写

FTP传输需要通过网页完成,所以我写了两个shell脚本文件(ftp_upload.sh, ftp_download.sh),由网页读取目标主机IP地址,然后根据传输需要,通过cgi程序读取文件名称执行不同的传输操作。

ftp_upload.sh:

#!/bin/shftp ‐v ‐n $1<user edision soc20174 binarycd /home/edision/Downloadlcd uftppromptput $2byeEOFecho "commit to ftp successfully"

$1参数为目标主机的IP地址,$2为上传文件名

ftp_download.sh:

#!/bin/shftp ‐v ‐n $1<user edision soc2017binarycd /home/edision/Downloadlcd uftppromptget $2byeEOFecho "download from ftp successfully"

$1参数为目标主机的IP地址,$2为下载文件名

通过cgi程序接收到IP地址和文件名后,根据传输类型的不同,选择对应的脚本文件,然后执行。这里我的文件传输通过多线程是支持多用户连接的,可以极大提高传输效率。然后定义了一个URL译码程序,在用户传输特殊字符(这里主要是路径斜线),可以将传输的URL码转译为对应的特殊符号。

云计算demo

socket服务器端与客户端通信过程

2f36c7013cc0e38e5e73eab8f7c505ee.png

  • 从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;

  • 服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;

  • 客户端收到服务器的SYN K ,ACKJ+1之后,这时connect返回,并对SYN K进行确认;

  • 服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

socket中TCP的握手释放连接

4b4e33bff8b962b4bd3034426c5663a8.png

  • 某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;

  • 另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;

  • 一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;

  • 接收到这个FIN的源发送端TCP对它进行确认。

服务器程序设计:

本次设计的程序需要支持多用户连接,因此我设计了多线程连接的思想,来为每一个客户的访问申请一个子线程。

所以首先定义了sgi_handler函数用于获取子进程退出信号,在退出时给出提示信息。然后在用户输入add/sub/mul/div op1 op2来去执行运算以获得返回结果。程序主体:

1. 首先定义了一个结构体,存储操作符和数据。

2. 子进程退出提示信号函数。

3. 创建socket()描述符用于标示唯一的socket,然后赋予其协议域,socke类型以及指定协议。

4. bind()函数把ipv4地址和端口号赋予socket。

5. listen()函数监听这个socket,如果客户端调用connect()发出连接请求,服务器就可以接收到这个请求。

6. TCP服务器端监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。

7. 之后通过fork()函数创建子进程,通过read函数读取内容进行处理,并通过write函数将结果写回到客户端,并等待下一条命令的输入。

客户端程序设计

发送add/sub/mul/div op1 op2指令到服务器端,获得返回的结果。结构相对服务器端不用考虑多线程的问题,结构较为简单。

1. 首先定义了一个结构体,存储操作符和数据。

2. 创建socket()描述符用于标示唯一的socket,然后赋予其协议域,socke类型以及指定协议。

3. bind()函数把ipv4地址和端口号赋予socket。

4. listen()函数监听这个socket,如果客户端调用connect()发出连接请求,服务器就可以接收到这个请求。

5. 客户端向服务端发送连接请求

6. 连接成功之后向服务器发送命令并等待返回结果。

两个程序设计的源码,可以点击“阅读原文”下载。

成果运行示例:

c90270aa919ba5e24741ddde31169805.png

服务器端:

30ff69bba4e744b3db9dd50870d6c828.png

总结

这次实验首先是服务器的移植,让我了解了网页的制作。然后明白浏览器是怎么通过IP地址来去访问服务器,真是深感神奇。

第一次做出来了自己期望的网页界面(虽然很简陋),从网页的学习我现在有明白了之前爬虫爬下来网页的内容的含义,对我以后制作自动下载的脚本帮助甚大。

第二个是要在页面能够配置IP。我思索了整整两天,最开始是希望通过能够在网页上书写javascript来去修改本地的rcS文件,但是这个想法真的是纯属异想天开,最终选择放弃。后来经过仔细调研最终选择了通过cgi程序来去和浏览器完成数据的交互,这给我开启了一个新世界的大门,如果可以这样的话,我可以通过网页发送期望的数据来完成和开发板的交互。

第三个通过TCP协议完成文件的传输。原本我想的是在开发板上配置vsftpd,然后通过远程ftp访问,但是发现面临无法调用用户端的脚本文件的问题,因此转换了一下思路,在目标主机上安装vsftpd,在开发板上运行ftp,这种思维转为又给我带来了新的灵感。然后shell脚本也会编写了,嵌入式真是一门综合性的学科。

最后socket编程的学习让我了解了服务器和用户是怎么完成网络通信的。

以上三篇便是我在设计嵌入式开发板云计算平台的搭建过程中分享的全部内容,流程及重点要关注的地方也给大家提示了,希望大家都可以轻松的搭建自己的云计算平台!

如果在开发中遇到问题,我在达尔闻技术交流群里等着你!

8c002330c487267cc13457f17b93da1e.png

aa7a5c67ccb9bc4149665a3531646aaa.png

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值