嵌入式培训经验分享——实现基于Qt和Linux的ftp协议通信

我们在使用Qt和Linux实现fpt文件传输协议时,需要将服务器运行在Linux系统上,使用Qt来编写客户端,用Qt实现实现一个界面从客户端可以访问与服务器之间的共享目录,实现上传和下载的功能。

1、客户端

客户端主要是实现一个界面的可视化,并且完成与服务器的连接,命令的发送和接收。

可视化界面:

 客户端的主要代码:

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QTcpSocket>
#include <QSize>
#include <QListWidgetItem>
#include  <cstring>
#include <QFileDialog>
#include <QFile>
#include <QFileInfo>
#include <QThread>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->progressBar->setValue(0);
    ui->progressBar->setVisible(false);
    p_Msg = new ftp_msg;
    memset(p_Msg,0,sizeof(*p_Msg));
    ui->lineEditIP->setText("192.168.0.106");
    ui->lineEditPORT->setText("9998");
    //第一步 创建socket对象 绑定信号
    pCli = new QTcpSocket;
    connect(pCli,SIGNAL(readyRead()),this,SLOT(SocketReadyreadSlotFun()),Qt::QueuedConnection);
    connect(pCli,SIGNAL(connected()),this,SLOT(SocketConnectedSlotFun()));
    connect(pCli,SIGNAL(disconnected()),this,SLOT(SocketDisConnectedSlotFun()));
    //第二步 当用户点击连接按钮,发起connect请求
    connect(ui->btnConnect,SIGNAL(clicked()),this,SLOT(btnConnectClickedSlotFun()));
    //第三步 设置其他的信号与槽函数
    connect(ui->btnLook,SIGNAL(clicked()),this,SLOT(btnLookClickedSlotFun()));
    connect(ui->btnDown,SIGNAL(clicked()),this,SLOT(btnDownClickedSlotFun()));
    connect(ui->btnUp,SIGNAL(clicked()),this,SLOT(btnUpClickedSlotFun()));

}

Widget::~Widget()
{
    delete ui;
}

void Widget::btnConnectClickedSlotFun()
{
    QString ip = ui->lineEditIP->text();
    QString strport = ui->lineEditPORT->text();
    unsigned short port = strport.toUShort();
    pCli->connectToHost(ip,port);
    bool ok = pCli->waitForConnected(80);
    if(ok == false)
    {
        QMessageBox::warning(this,"警告,连接失败","请保持网络畅通,可能服务器不存在",QMessageBox::Yes);
        return ;
    }

    ui->btnConnect->setText("断开");
}

void Widget::SocketReadyreadSlotFun()
{
    struct ftp_msg *p_Msg = new ftp_msg;
    memset(p_Msg,0,sizeof(*p_Msg));
    int ret = pCli->read((char *)p_Msg,sizeof(*p_Msg));
    if(ret<0)
    {
        QMessageBox::warning(this,"警告,连接失败","请检查连接",QMessageBox::Yes);
        return;
    }

    //qDebug()<<p_Msg->cmd<<endl;
    switch (p_Msg->cmd) {
    case 1:
        for(int i=0;i<p_Msg->len;i++)
        {
            QString str = p_Msg->response[i];
            char *ret = strstr(p_Msg->response[i],".");
            if(ret == NULL)
            {
                //创建item
                QSize sz(80,40);
                pItem=new QListWidgetItem;
                pItem->setSizeHint(sz);
                QIcon icon(":/file.ico");
                pItem->setIcon(icon);
                pItem->setText(p_Msg->response[i]);
            }else
            {
                QSize sz(80,40);
                pItem=new QListWidgetItem;
                pItem->setSizeHint(sz);
                QIcon icon(":/text.ico");
                pItem->setIcon(icon);
                pItem->setText(p_Msg->response[i]);
            }
            ui->listWidgetFile->addItem(pItem);
            ui->listWidgetFile->setViewMode(QListWidget::ListMode);
        }
        break;
    case 2:{
            ui->progressBar->setVisible(true);
            bool ok = file.write((char *)p_Msg->filebuf, sizeof(p_Msg->filebuf) );
            if(ok==false){
                QMessageBox::warning(this,"警告,写入失败","请文件是否存在",QMessageBox::Yes);
                return;
            }

            //qDebug()<<"down load txt:"<<p_Msg->filebuf;
            if(p_Msg->endfileflag == 1)
            {
                file.close();
                ui->progressBar->setValue(0);
                ui->progressBar->setVisible(false);
                memset(p_Msg,0,sizeof(*p_Msg));
            }
            Sret+=sizeof(p_Msg->filebuf);
            val = Sret/p_Msg->len;
            //ui->lbl->setText(QString::number(Sret));
            ui->progressBar->setValue(int(val*100));
            memset(p_Msg,0,sizeof(*p_Msg));
        break;

        }
    }

}

void Widget::SocketConnectedSlotFun()
{

}

void Widget::SocketDisConnectedSlotFun()
{
    ui->btnConnect->setText("连接");
    pCli->disconnectFromHost();
    pCli->close();
}

void Widget::btnLookClickedSlotFun()
{
    memset(p_Msg,0,sizeof(*p_Msg));
    p_Msg->cmd = 1;
    pCli->write((char *)p_Msg,sizeof(*p_Msg));
}

void Widget::btnDownClickedSlotFun()
{
    //QString str = ui->listWidgetFile->currentItem()->text();
    //qDebug()<<str<<endl;

    memset(p_Msg,0,sizeof(*p_Msg));
    p_Msg->cmd = 2;
    int p = ui->listWidgetFile->currentRow();
    if(p<0)
    {
        QMessageBox::about(this,"下载失败","请选择文件");
        return;
    }
    QString fn = ui->listWidgetFile->currentItem()->text();
    if(fn.isEmpty())
    {
        QMessageBox::about(this,"下载失败","请选择文件");
        return;
    }
    //qDebug()<<fn.toStdString().c_str()<<endl;
    strcpy(p_Msg->filename,fn.toStdString().c_str());
    qDebug()<<p_Msg->filename<<endl;
    QString str = "D:/Qt(C++)/project/Qt-ftp/test/" + fn;
    //qDebug()<<str<<endl;
    QString filename = QFileDialog::getSaveFileName(this,"请选择你要保存的路径",str, "*.c;*.h;*.txt");
    if(filename.isEmpty() ){// filename == ""
        return;
    }
    qDebug()<<filename<<endl;

    file.setFileName(filename);
    bool ok = file.open(QIODevice::WriteOnly);
    if(ok==false){
        QMessageBox::warning(this,"警告,创建失败","请检查正确路径",QMessageBox::Yes);
        return;
    }
    pCli->write((char *)p_Msg,sizeof(*p_Msg));
    memset(p_Msg,0,sizeof(*p_Msg));
    Sret= 0;val= 0;
}

void Widget::btnUpClickedSlotFun()
{
    memset(p_Msg,0,sizeof(*p_Msg));
    p_Msg->cmd = 3;

    QString filename = QFileDialog::getOpenFileName(this,"请选择文件","D:/Qt(C++)/project/Qt-ftp/test/","*.txt;*.c;*.h");
       if(filename.isEmpty() ){
           QMessageBox::about(this,"提示框","请选择文件");
           return;
       }
    QString fn = filename.right(filename.length()-filename.lastIndexOf('/')-1);
    //qDebug()<<fn<<endl;
    strcpy(p_Msg->filename,fn.toStdString().c_str());
    //创建Qfile对象,并绑定到具体文件上
    QFile file(filename);
    QFileInfo fileinfo(filename);
    bool ok = file.open(QIODevice::ReadOnly);
    if(ok==false){
        QMessageBox::warning(this,"警告","文件上传失败",QMessageBox::Yes);
        return;
    }
    pCli->write((char *)p_Msg,sizeof(*p_Msg));
    Sret= 0;val= 0;
    qDebug()<<"open success"<<endl;
    ui->progressBar->setValue(0);
    ui->progressBar->setVisible(true);
    while(1){
        memset(p_Msg->filebuf,0,sizeof(p_Msg->filebuf));
        int ret = file.read((char *)p_Msg->filebuf,sizeof (p_Msg->filebuf));
        if(ret == 0){
            break;
        }else if(ret<0){
            QMessageBox::warning(this,"文件读取失败","文件读取失败了",QMessageBox::Yes);
            file.close();
            return ;
        }
        Sret+=ret;
        val = Sret/fileinfo.size();
        //ui->lbl->setText(QString::number(Sret));
        ui->progressBar->setValue(int(val*100));
        QThread::msleep(100);

        //qDebug()<<"up load txt:"<<p_Msg->filebuf;
        pCli->write((char *)p_Msg,sizeof(*p_Msg));

    }
    ui->progressBar->setValue(0);
    ui->progressBar->setVisible(false);
    memset(p_Msg,0,sizeof(*p_Msg));
    p_Msg->cmd = 3;
    p_Msg->endfileflag=1;
    pCli->write((char *)p_Msg,sizeof(*p_Msg));
    file.close();

}

2、服务器

服务器主要需要实现对命令的接收和对应的操作等等,和客户端相互配合完成文件的上传和下载的功能。服务器的部分代码:

#include <stdio.h>	 
#include <sys/types.h>          
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include "commen.h"
#include <sys/stat.h>
#include <fcntl.h>

#include <errno.h>
struct pthread_serv_msg{
	pthread_t tid;
	int cli_socket;
};



void *serv_for_client(void *args)
{
	int ret;
	struct pthread_serv_msg *pmsg=args;
	int socket = pmsg->cli_socket;
	struct ftp_msg serv_msg;
	while(1){
		memset(&serv_msg,0,sizeof(serv_msg));
		ret = recv(socket,&serv_msg,sizeof(serv_msg),0);
		if(ret < 0)
		{
			perror("recv err");
			close(socket); free(pmsg);return NULL;
		}else if(ret == 0)
		{
			close(socket); free(pmsg);return NULL;
		}
		//printf("serv got serv_msg:%s\n",rxbuf);
		switch(serv_msg.cmd){
		case 1:  //list   获取当前目录下的内容   readdir()
			{  
				DIR *dir = opendir("./");
				if(dir==NULL)
				{
					perror("file opendir err");
					return NULL;
				}
				int i=0,j=0;
				while(1)
				{
					struct dirent *rent = readdir(dir);
					if(rent==NULL)
					{
						//for(int n=0;n<i;n++)
						//{
							//printf("%s\n",serv_msg.response[n]);
						//}
						serv_msg.len=i;
						break;
					}
					if(strcmp(rent->d_name,".")==0 || strcmp(rent->d_name,"..")==0)
					{
						continue;
					}
					//printf("%6s :%d\n",rent->d_name,rent->d_type);
					strcpy(serv_msg.response[i++],rent->d_name);
					//snprintf(serv_msg.response,sizeof(serv_msg.response),\
							"  %s  %s  ",serv_msg.response,rent->d_name);
					
				}
				
				closedir(dir);
				
				ret = send(socket,&serv_msg,sizeof(serv_msg),0);
				if(ret < 0)
				{
					perror("serv send err");
					return NULL;
				}
				break;
			}
		case 2:
			{
				//char buf[64]={0};
				//snprintf(buf,sizeof(buf),".\\comm\\%s",serv_msg.filename);
				int fd = open(serv_msg.filename, O_CREAT|O_RDWR,0666);
				if(fd < 0){
					perror("open err");
					return NULL;
				}
				serv_msg.len = lseek(fd,0,SEEK_END);
				if(serv_msg.len <0){
					perror("lseek err");
					return NULL;
				}
				printf("open success:%d\n",serv_msg.len);
				lseek(fd,0,SEEK_SET);
				while(1){
					memset(serv_msg.filebuf,0,sizeof(serv_msg.filebuf));
					ret = read(fd,serv_msg.filebuf,sizeof(serv_msg.filebuf)-1);
					if(ret < 0 ){
						perror("read err");
						return NULL;
					}else if(ret ==0){
						//send(socket,&serv_msg,sizeof(serv_msg),0);
						printf("end of file\n");
						break;
					}else if(ret < sizeof(serv_msg.filebuf)-1)
					{
						serv_msg.endfileflag = 1;
					}
					serv_msg.cmd=2;
					ret = send(socket,&serv_msg,sizeof(serv_msg),0);
					if(ret < 0)
					{
						perror("serv send err");
						return NULL;
					}
					//printf("%s",serv_msg.filebuf);
					usleep(100*1000);
				}
				printf("\n");
				ret = close(fd);
				if(ret <0){
					perror("close err");
					return NULL;
				}
				break;
			}
		case 3:
			{
				//创建一个空文件 
				int fd = open(serv_msg.filename, O_CREAT|O_RDWR,0666);
				if(fd < 0)
				{
					perror("open err");
					return NULL;
				}
				printf("file creat success\n");
				while(1)
				{
					memset(&serv_msg,0,sizeof(serv_msg));
					ret = recv(socket,&serv_msg,sizeof(serv_msg),0);
					if(ret < 0)
					{
						perror("recv err");
						return NULL;
					}
					ret  = write(fd,serv_msg.filebuf,strlen(serv_msg.filebuf));
					if(ret < 0 ){
						perror("write err");
						return NULL;
					}
					//printf("%s\n",serv_msg.filebuf);
					//如果发现对方最后一次,结束while
					if(serv_msg.endfileflag == 1)
					{
						printf("upload success\n");
						break;
					}
					
				}
				ret = close(fd);
				if(ret <0){
					perror("close err");
					return NULL;
				}
				break;
			}
		}
	}
	close(socket);
	 free(pmsg);
	return NULL;
}


int main()
{
	int socket_main = socket(AF_INET,SOCK_STREAM,0);
	if(socket_main < 0)
	{
		perror("socket creat err");
		return -1;
	}
	printf("socket success\n");
	struct sockaddr_in serv_addr;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(9998);
	serv_addr.sin_addr.s_addr = inet_addr("192.168.0.106");
	
	int ret = bind(socket_main, (struct sockaddr *)&serv_addr  , sizeof(serv_addr));
	if(ret < 0)
	{
		perror("bind err");
		return -3;
	}
	printf("bind success\n");
	struct sockaddr_in cli_addr;
	socklen_t addrlen=sizeof(cli_addr);
	
	struct pthread_serv_msg *pserv_msg=NULL;
	int socket_new;

	ret = listen(socket_main,5);
	if(ret < 0)
	{
		perror("listen err");
		return -3;
	}
	printf("listen......\n");
loop:	
	socket_new = accept(socket_main,(struct sockaddr *)&cli_addr,&addrlen);
	if(socket_new < 0)
	{
		perror("accept err");
		return -3;
	}
	printf("accpet success\n");
	printf("serv accpet client ip=%s port=%d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));
	
	pserv_msg=malloc(sizeof(*pserv_msg));
	pserv_msg->cli_socket=socket_new;
	pthread_create(&pserv_msg->tid,NULL,serv_for_client,pserv_msg);
	pthread_detach(pserv_msg->tid);
	printf("success link\n");
	goto loop;
	
	close(socket_main);
	return 0;
}

在客户端与服务器通信的过程中,我们需要定义一个相同的结构体来传输文件:

#ifndef __COMMON_XXX_
#define __COMMON_XXX_
struct ftp_msg {
	char cmd;	 //命令  1-查看目录   2-下载    3-上传
	char filename[32];	//文件名
	char filebuf[128];  //文本内容
	int len;            //文本和目录名字的个数
	char response[32][32];//保存文本和目录的名字
	int endfileflag; //判断文本内容是否传输完成
};

#endif 

需要完成版请私信我!!!!!

完整版:(7条消息) 实现基于Qt和Linux的ftp协议通信(完整代码)-Linux文档类资源-CSDN文库

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 嵌入式系统设计与应用是指在特定应用领域中,使用嵌入式处理器和相关硬件资源,结合嵌入式操作系统和软件开发工具,设计和开发满足特定需求的嵌入式系统。 ARM Cortex-A8是一款高性能的嵌入式处理器,广泛应用于手机、平板电脑、智能电视等嵌入式设备中。它具有强大的计算能力和低功耗特性,能够提供快速、高效的数据处理和多任务处理能力。 Linux是一种开源的嵌入式操作系统,提供了丰富的软件资源和开发工具,可以满足各种嵌入式应用的需求。在使用ARM Cortex-A8和Linux进行嵌入式系统设计和应用时,可以借助Linux的强大功能和丰富的软件生态系统,快速开发出满足特定需求的嵌入式应用。 设计和开发嵌入式系统时,首先需要选择合适的硬件平台和操作系统。选择ARM Cortex-A8作为处理器可以得到高性能和低功耗的优势,而选择Linux作为操作系统可以借助其丰富的软件资源和开发工具。 然后,根据具体的嵌入式应用需求,对系统进行架构设计和软件模块划分。在嵌入式系统设计中,需要考虑系统的实时性、功耗控制、硬件接口与外设的驱动、应用程序的开发等方面。 在应用开发阶段,可以使用C/C++等编程语言,结合相应的开发工具,编写应用程序和驱动程序。同时,可以借助Linux的丰富资源,如网络协议栈、文件系统、数据库等,快速实现系统的功能。 最后,在系统调试和测试阶段,可以使用调试工具和仿真平台进行系统性能测试和调试,以确保系统的稳定性和可靠性。 综上所述,嵌入式系统设计与应用基于ARM Cortex-A8和Linux可以提供高性能、低功耗和丰富软件资源的优势,能够快速开发出满足特定需求的嵌入式应用。 ### 回答2: 嵌入式系统设计与应用是指将计算机系统嵌入到特定的电子设备中,以完成特定的功能。基于ARM Cortex-A8和Linux嵌入式系统设计与应用是指利用ARM Cortex-A8处理器和Linux操作系统来设计和开发嵌入式系统。 ARM Cortex-A8是一种高性能、低功耗的32位RISC处理器。它采用精简指令集架构,具有较高的运算能力和较低的能耗。Cortex-A8处理器广泛应用于嵌入式领域,可用于智能手机、平板电脑、汽车导航系统等各种嵌入式设备。 Linux是一种开源的操作系统内核,具有广泛的硬件支持和强大的软件生态系统。在嵌入式系统设计中,Linux提供了丰富的功能和驱动支持,能够提供稳定可靠的操作环境。同时,Linux还可以方便地进行定制和扩展,以满足各种应用需求。 在基于ARM Cortex-A8和Linux嵌入式系统设计中,我们可以利用Linux提供的运行时库、工具链以及开发环境来进行系统开发。可以利用C/C++编程语言来进行应用程序的开发,使用Linux提供的设备驱动程序来进行硬件的控制和交互。同时,我们还可以利用Linux的网络支持和文件系统功能来实现网络连接和数据存储。 综上所述,基于ARM Cortex-A8和Linux嵌入式系统设计与应用具有高性能、低功耗、可定制和可扩展等优势,可以适用于各种嵌入式设备的开发和应用。它在智能手机、平板电脑、汽车导航系统等领域具有广泛的应用前景。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值